又见最长单调递增子序列
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
给一个序列 X(x[1] , x[2] , x[3] ……) ,可以找出他的任意一个单调递增子序列如 x[i1] , x[i2] , x[i3] …… x[in]
它必须满足以下条件。
(1) X[i1] < X[i2] < …… < X[in];
(2) 1<= i1 <i2 < …… < in <= n
问题是:
(1)找到最长的单调递增子序列 ,输出长度 len
(2)在每个元素最多只能用一次的情况下,找出长度为len 的单调递增子序列有多少个,输出个数sum。
-
输入
-
多组测试数据,不超过100组.
每组输入数据包含两行。
第一行一个数字n,代表序列的长度,第二行包含 n 个数字ai,代表序列中每个元素的值。
n <= 500 , ai <= 10000
输出
每组测试数据输出有两行。第一行输出len,第二行输出sum。
思路 : 将所有在单调递增最长子序列上的点建立边,将长度最长为1的点与源点建边,长度为len 的与汇点建边,中间则将 i,j,建边(dp[i]+1==dp[j]),边的容量为1 ,为保证只用一次,将一个点拆成两个点,容量为1
#include<bits/stdc++.h> using namespace std; int min ( int x,int y) { return x<y?x:y; } const int inf = 0x3f3f3f3f; const int maxn = 10000;//点的数目 int e,head[maxn]; int level[maxn]; int q[maxn]; int a[maxn]; int dp[maxn]; struct node { int to ,val,next; } edge[200005];//边 void add_edge(int x,int y,int w) { edge[e].to = y; edge[e].val = w; edge[e].next =head[x]; head[x]= e++; edge[e].to = x; edge[e].val = 0; edge[e].next = head[y]; head[y] = e++; } bool bfs(int s,int t) { int front =0; int rear = 0; int top,k; q[rear++] = s; memset(level,0,sizeof(level)); level[s] =1; while(front<rear) { top = q[front++]; if(top==t) return true; for(int k = head[top]; k!=-1; k=edge[k].next) { if(!level[edge[k].to]&&edge[k].val>0) { level[edge[k].to] = level[top]+1; q[rear++] = edge[k].to; } } } return false; } int dfs(int now,int maxf,int t) { int ret =0,f,k; if(now==t) return maxf; for(int k = head[now]; k!=-1; k = edge[k].next) { if(level[edge[k].to]==level[now]+1&&edge[k].val>0) { f = dfs(edge[k].to,min(maxf -ret,edge[k].val),t); edge[k].val-=f; edge[k^1].val+=f; ret+=f; if(ret==maxf) return ret ; } } if(ret==0) level[now] = 0; return ret; } int dinic(int s,int t) { int ans = 0; while(bfs(s,t)) ans+=dfs(s,inf,t); return ans; } int main() { int n; while(scanf("%d",&n)!=EOF) { memset(head,-1,sizeof(head)); memset(dp,0,sizeof(dp)); e = 0; for(int i = 1; i<=n; i++) { scanf("%d",&a[i]); } int len = 1; for(int i = 1; i<=n; i++) { dp[i] = 1; for(int j= i-1; j>=1; j--) { if(a[i]>a[j]&&dp[i]<dp[j]+1) { dp[i]= dp[j]+1; } } len = max(dp[i],len); int v = dp[i]; for(int j= i-1; j>=1; j--) { if(a[i]>a[j]&&v==dp[j]+1) { add_edge(j+n,i,1); } } } if(len==1) { printf("%d\n",len); printf("%d\n",n); continue; } int s = 0; int t = 2*n+1; for(int i= 1; i<=n; i++) { if(dp[i]==len) { add_edge(i+n,t,1); } if(dp[i]==1) { add_edge(s,i,1); } add_edge(i,i+n,1); } printf("%d\n",len); printf("%d\n",dinic(s,t)); } return 0; }
-
多组测试数据,不超过100组.