Sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 946 Accepted Submission(s): 325
Problem Description
There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequence of X
as x[i1], x[i2],...,x[ik], which satisfies follow conditions:
1) x[i1] < x[i2],...,<x[ik];
2) 1<=i1 < i2,...,<ik<=n
As an excellent program designer, you must know how to find the maximum length of the
increasing sequense, which is defined as s. Now, the next question is how many increasing
subsequence with s-length can you find out from the sequence X.
For example, in one case, if s = 3, and you can find out 2 such subsequence A and B from X.
1) A = a1, a2, a3. B = b1, b2, b3.
2) Each ai or bj(i,j = 1,2,3) can only be chose once at most.
Now, the question is:
1) Find the maximum length of increasing subsequence of X(i.e. s).
2) Find the number of increasing subsequence with s-length under conditions described (i.e. num).
as x[i1], x[i2],...,x[ik], which satisfies follow conditions:
1) x[i1] < x[i2],...,<x[ik];
2) 1<=i1 < i2,...,<ik<=n
As an excellent program designer, you must know how to find the maximum length of the
increasing sequense, which is defined as s. Now, the next question is how many increasing
subsequence with s-length can you find out from the sequence X.
For example, in one case, if s = 3, and you can find out 2 such subsequence A and B from X.
1) A = a1, a2, a3. B = b1, b2, b3.
2) Each ai or bj(i,j = 1,2,3) can only be chose once at most.
Now, the question is:
1) Find the maximum length of increasing subsequence of X(i.e. s).
2) Find the number of increasing subsequence with s-length under conditions described (i.e. num).
Input
The input file have many cases. Each case will give a integer number n.The next line will
have n numbers.
have n numbers.
Output
The output have two line. The first line is s and second line is num.
Sample Input
4
3 6 2 5
Sample Output
2
2
Source
Recommend
lcy
思路:思路跟最短路径+最大流是一样的,用最大流去限定,求出最短路径的个数。同样,求出最长上升子序列,再用最大流去限定,求出的结果就是最长上升子序列的个数。求LCIS则用常规方法,既定义数组dp[i]是表示以 i 结尾的最长上升子序列的长度,求出最长序列ans。由于数列中的每一个数只能使用一次,构图的时候需要拆点。若有n个数,则拆成2 * n个点,构造源点和汇点,将每个点都和自己拆出来的点连边,将源点和最长序列为1的点连边,将最长序列为ans的点与汇点连边,最后若dp[j] = dp[i] + 1,则将i + n和 j连边。所有边的流量都是1,这样便可以限制每个点只使用一次。其实连边的顺序就是最长序列为1,2,3,...,ans。可以理解为从最长序列为1(该数本身)一直流到数列中的最长上升序列。画出图来就好理解了。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=500010; const int INF=0x3f3f3f3f; struct Edge{ int to,nxt; int cap; }edge[N<<1]; int n,cnt,head[N],dp[N],num[N]; int dep[N],gap[N],cur[N],aug[N],pre[N]; void addedge(int cu,int cv,int cw){ edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu]; head[cu]=cnt++; edge[cnt].to=cu; edge[cnt].cap=0; edge[cnt].nxt=head[cv]; head[cv]=cnt++; } int LCIS(){ //求出最长上升子序列 for(int i=1;i<=n;i++) dp[i]=1; // dp[i]是表示以 i 结尾的最长上升子序列的长度 int ans=0; for(int i=1;i<=n;i++){ for(int j=1;j<i;j++) if(num[i]>num[j] && dp[j]+1>dp[i]) dp[i]=dp[j]+1; ans=max(ans,dp[i]); } return ans; } int src,des; int SAP(int n){ int max_flow=0,u=src,v; int id,mindep; aug[src]=INF; pre[src]=-1; memset(dep,0,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0]=n; for(int i=0;i<=n;i++) cur[i]=head[i]; // 初始化当前弧为第一条弧 while(dep[src]<n){ int flag=0; if(u==des){ max_flow+=aug[des]; for(v=pre[des];v!=-1;v=pre[v]){ // 路径回溯更新残留网络 id=cur[v]; edge[id].cap-=aug[des]; edge[id^1].cap+=aug[des]; aug[v]-=aug[des]; // 修改可增广量,以后会用到 if(edge[id].cap==0) // 不回退到源点,仅回退到容量为0的弧的弧尾 u=v; } } for(int i=cur[u];i!=-1;i=edge[i].nxt){ v=edge[i].to; // 从当前弧开始查找允许弧 if(edge[i].cap>0 && dep[u]==dep[v]+1){ // 找到允许弧 flag=1; pre[v]=u; cur[u]=i; aug[v]=min(aug[u],edge[i].cap); u=v; break; } } if(!flag){ if(--gap[dep[u]]==0) /* gap优化,层次树出现断层则结束算法 */ break; mindep=n; cur[u]=head[u]; for(int i=head[u];i!=-1;i=edge[i].nxt){ v=edge[i].to; if(edge[i].cap>0 && dep[v]<mindep){ mindep=dep[v]; cur[u]=i; // 修改标号的同时修改当前弧 } } dep[u]=mindep+1; gap[dep[u]]++; if(u!=src) // 回溯继续寻找允许弧 u=pre[u]; } } return max_flow; } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d",&n)){ cnt=0; memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) scanf("%d",&num[i]); int ans=LCIS(); src=0; des=2*n+1; for(int i=1;i<=n;i++){ addedge(i,n+i,1); //将每个点都和自己拆出来的点连边, 容量为1 if(dp[i]==1) //将源点和最长序列为1的点连边 addedge(src,i,1); if(dp[i]==ans) //将最长序列为ans的点与汇点连边 addedge(n+i,des,1); for(int j=i+1;j<=n;j++) if(dp[j]==dp[i]+1) //最后若dp[j] = dp[i] + 1,则将i + n和 j连边 addedge(n+i,j,1); //所有边的流量都是1,这样便可以限制每个点只使用一次 } printf("%d\n%d\n",ans,SAP(2*n+2)); } return 0; }
相关推荐
Problem Description 话说,经过了漫长的一个多月,小明已经成长了许多,所以他改了一个名字叫“大明”。 这时他已经不是那个只会做100以内加法的那个“小明”了,现在他甚至会任意长度的正小数的加法。...
从简单入门到偏中等的几个题,线段树很灵活,主要懂了lazy操作,其他的自己yy吧。
本人准备2020年保研机试时刷的题目(虽然最后机试取消了,...来自某中流985,在HDU和vjudge平台上大概刷了400道。本文件地图(excel表格)包含了绝大部分我刷过的题目,笔记中具有思路、代码、总结和心得。 大佬勿入!
HDU的一题........HDU DP动态规
acm入门之枚举搜索,学校第一次acm培训,包括枚举及其优化,dfs和bfs
ACM题库,一些题目和答案,以及解题报告,传上来共享
hdu 3341(ac自动机+状态压缩) 题意:容易理解... 思路:首先一开始容易想到要用到dp,开设一个dp[41][41][41][41][501]的数组来解决,但是明显内存已经超出范围了,于是就想如何减少内存呢?只要知道A、T、C、G其中...
杭电OnlineJudge 200-2099的解题报告
2、new做两件事,一是分配内存,二是调用类的构造函数 3、new建立的是一个对象,而malloc分配的是一块内存 4、new/delete是保留字,不需要头文
动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,...
HDU上DP大集合,里面包括题,题解,代码,对DP入门者很实用,对DP老手也是有很大的提高
300+ AC 代码 。 大数 , 线段树 , 字符串 , dp.....
acm hdu as easy as a+b
hdu 1695 GCD(欧拉函数+容斥原理).docx
动态规划DP题解 POJ HDU部分动态规划DP题解
HDU-1711 Number Sequence(KMP算法)For each test case, you should output one line wh
hdu 1005.比较简单的一道题,有兴趣的可以看看。
HDU的1250,主要是利用高精度加法,但是代码有点繁琐,效率不是很高
HDU1059的代码
杭电ACMhdu1163