最长不下降子序列问题
问题描述
给定正整数序列x1,...,xn 。
(1)计算其最长不下降子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列。
输入格式
第1 行有1个正整数n,表示给定序列的长度。接下来的1 行有n个正整数n:x1, ..., xn。
输出格式
第1 行是最长不下降子序列的长度s。第2行是可取出的长度为s 的不下降子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的不下降子序列个数。
首先用n^2算出f[i],开头为i的最长不下降子序列
通过放f[i]分层建图:
1、把数列每位i拆成两个点,连接一条容量为1的有向边。
2、建立源点s和汇点t,如果数列第i位有f[i]=ans,从s到<i.a>连接一条容量为1的有向边。如果f[i]=1,从<i.b>到T连接一条容量为1的有向边。
3、如果i<j且a[i] < =a[j]且f[j]+1=f[i],从<i.b>到<j.a>连接一条容量为1的有向边。
保证每一条从s到t的路径都是满足长度为ans的序列
第二问:序列最多能得到不重复下标的序列数
第三问:序列最多能得到(除了1,n)不重复下标的序列数;
#include<bits/stdc++.h> #define re return #define dec(i,l,r) for(int i=l;i>=r;--i) #define inc(i,l,r) for(int i=l;i<=r;++i) using namespace std; template<typename T>inline void rd(T&x) { char c;bool f=0; while((c=getchar())<'0'||c>'9')if(c=='-')f=1; x=c^48; while((c=getchar())>='0'&&c<='9')x=x*10+(c^48); if(f)x=-x; } const int maxn=2000,inf=2147483647; int n,m,k=1,s,t,hd[maxn],cur[maxn],a[505],f[505]; int deep[maxn]; struct node{ int to,nt,flow; }e[100005]; inline void add(int x,int y,int flow) { e[++k].to=y;e[k].nt=hd[x];hd[x]=k;e[k].flow=flow; e[++k].to=x;e[k].nt=hd[y];hd[y]=k;e[k].flow=0; } inline bool bfs() { inc(i,1,t)deep[i]=0; deep[s]=1; queue<int>q; q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); for(int i=hd[x];i;i=e[i].nt) { int v=e[i].to; if(deep[v]==0&&e[i].flow) { deep[v]=deep[x]+1; if(v==t)re 1; q.push(v); } } } re 0; } inline int dfs(int x,int flow) { if(x==t)re flow; int delta=flow; for(int &i=cur[x];i;i=e[i].nt) { int v=e[i].to; if(deep[v]==deep[x]+1&&e[i].flow) { int d=dfs(v,min(delta,e[i].flow)); e[i].flow-=d; e[i^1].flow+=d; delta-=d; if(!delta)re flow; } } re flow-delta; } int main() { // freopen("in.txt","r",stdin); int ans=0; rd(n); s=n+n+1;t=s+1; inc(i,1,n)rd(a[i]); dec(i,n,1) { f[i]=1; inc(j,i+1,n) if(a[i]<=a[j])f[i]=max(f[i],f[j]+1); ans=max(ans,f[i]); } printf("%d\n",ans); inc(i,1,n) { add(i,i+n,1); if(f[i]==ans) add(s,i,1); if(f[i]==1) add(i+n,t,1); inc(j,i+1,n) if(a[i]<=a[j]&&f[i]==f[j]+1) add(i+n,j,1); } int ANS=ans; ans=0; while(bfs()) { inc(i,1,t)cur[i]=hd[i]; ans+=dfs(s,inf); } printf("%d\n",ans); for(int i=2;i<=k;i+=2) { e[i].flow+=e[i^1].flow; e[i^1].flow=0; } if(f[1]==ANS)add(s,1,inf); //保证建图正确,s与f[i]=ans的点连边 add(1,n+1,inf); add(n,n+n,inf); add(n+n,t,inf); ans=0; while(bfs()) { inc(i,1,t)cur[i]=hd[i]; ans+=dfs(s,inf); } printf("%d\n",ans); re 0; }