«问题描述:
给定正整数序列$x_1,...,x_n$ 。$n<=500$
求(1)计算其最长不下降子序列的长度$s$。
(2)计算从给定的序列中最多可取出多少个长度为$s$的不下降子序列。
(3)如果允许在取出的序列中多次使用$x_1$和$x_n$,则从给定序列中最多可取出多少个长度为$s$的不下降子序列。
(1)暴力n方解决
(2)建分层图,把图每个顶点i按照F[i]的不同分为若干层,这样图中从S出发到T的任何一条路径都是一个满足条件的最长不下降子序列。由 S 向所有$ f_i = 1$ 的$ i $连容量为$ 1 $的边,由 所有$ f_i = s $的$ i $向$ T $连容量为$ 1$ 的边。对于所有的$ (i,j)$,若$ i < j,f_i +1 = f_j$,则由$ i$ 向$ j$ 连容量为 $1$ 的边。这样一来,所 有从 $S$ 出发到达$ T$ 的的路径都是一个长度为 $s $的上升子序 列。
注意拆点,以保证同一个数不会重复使用。一个连入边,一个连出边,两个点 之间连流量为 1 的限制边。
注意事项: line49的条件判断注意$f[j]+1==f[i]$的前提是要$a[j]<=a[i]$才可以连边!
(3)把之前的边的流量限制改一下即可,对1号和n号微调后原样跑。
注意事项(其实网上绝大部分题解好像都忽略了):建边时s向1号点的容量不可为无穷,应设为n, n号点连t同理.
比如这个毒瘤数据
1
1
绝大部分题解输的是INF,但其实是1
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef pair<int,int> pii; 5 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 6 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 7 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 8 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 9 template<typename T>inline T read(T&x){ 10 x=0;char c;while(!isdigit(c=getchar()))if(isalpha(c))return x=(int)c; 11 while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return x; 12 } 13 const int N=500+7,M=150000+7,INF=0x3f3f3f3f; 14 int w[2][M<<1],v[2][M<<1],Next[2][M<<1],Head[2][N<<1],cur[2][N<<1],dis[2][N<<1],tot[2],s,t,n; 15 inline void Addedge(int x,int y,int z,int p){ 16 v[p][++tot[p]]=y,Next[p][tot[p]]=Head[p][x],Head[p][x]=tot[p],w[p][tot[p]]=z; 17 v[p][++tot[p]]=x,Next[p][tot[p]]=Head[p][y],Head[p][y]=tot[p],w[p][tot[p]]=0; 18 } 19 #define y v[p][j] 20 inline char bfs(int p){ 21 queue<int> q;q.push(s),memset(dis[p],0,sizeof dis[p]),dis[p][s]=1; 22 for(register int i=1;i<=(n<<1)+2;++i)cur[p][i]=Head[p][i]; 23 while(!q.empty()){ 24 int x=q.front();q.pop(); 25 for(register int j=Head[p][x];j;j=Next[p][j])if(w[p][j]&&!dis[p][y]){ 26 dis[p][y]=dis[p][x]+1,q.push(y); 27 if(y==t)return 1; 28 } 29 } 30 return 0; 31 } 32 int dinic(int x,int flow,int p){ 33 if(!flow||x==t)return flow; 34 int rest=flow,k; 35 for(register int j=cur[p][x];j&&rest;cur[p][x]=j,j=Next[p][j])if(w[p][j]&&dis[p][y]==dis[p][x]+1){ 36 if(!(k=dinic(y,_min(rest,w[p][j]),p)))dis[p][y]=0; 37 rest-=k,w[p][j]-=k,w[p][j^1]+=k; 38 } 39 return flow-rest; 40 } 41 #undef y 42 int a[N],f[N],ans,maxflow; 43 44 int main(){//freopen("P2766.in","r",stdin);//freopen("P2766.txt","w",stdout); 45 read(n);s=(n<<1)+1,t=s+1,tot[0]=tot[1]=1; 46 for(register int i=1;i<=n;++i){ 47 read(a[i]);f[i]=1; 48 for(register int j=1;j<i;++j)if(a[j]<=a[i])MAX(f[i],f[j]+1); 49 for(register int j=1;j<i;++j)if(f[j]+1==f[i]&&a[j]<=a[i])Addedge(j+n,i,1,0),Addedge(j+n,i,1,1); 50 MAX(ans,f[i]),Addedge(i,i+n,1,0);if(f[i]==1)Addedge(s,i,1,0),i==1?Addedge(s,i,n,1):Addedge(s,i,1,1); 51 if(i==1||i==n)Addedge(i,i+n,n,1);else Addedge(i,i+n,1,1); 52 } 53 printf("%d ",ans); 54 for(register int i=1;i<=n;++i)if(f[i]==ans)Addedge(i+n,t,1,0),i==n?Addedge(i+n,t,n,1):Addedge(i+n,t,1,1); 55 while(bfs(0))maxflow+=dinic(s,n,0); 56 printf("%d ",maxflow);maxflow=0; 57 while(bfs(1))maxflow+=dinic(s,n,1); 58 printf("%d ",maxflow); 59 return 0; 60 }