先dp 再网络流。。。。题解中说要拆点。。其实是为了防止最长序列为1时 再往下求会出错的问题。。。也可以不拆点特判一下就可以了。。。。
这个是分层图的简单应用。。。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define inf 100000000 #define N 200000 #define M 2000 #define cc(m,v) memset(m,v,sizeof(m)) struct node{ int u,v,f,next; }edge[N]; int head[M],p,lev[M],cur[M]; int que[N]; void ainit(){ p=0,cc(head,-1); } void addedge(int u,int v,int w){ edge[p].u=u,edge[p].v=v,edge[p].f=w,edge[p].next=head[u],head[u]=p++; edge[p].u=v,edge[p].v=u,edge[p].f=0,edge[p].next=head[v],head[v]=p++; } bool bfs(int s,int t){ int i,u,v,qin=0,qout=0; cc(lev,0),lev[s]=1,que[qin++]=s; while(qout!=qin){ u=que[qout++]; for(i=head[u];i!=-1;i=edge[i].next) if(edge[i].f>0 && !lev[v=edge[i].v]){ lev[v]=lev[u]+1,que[qin++]=v; if(v==t) return 1; } } return 0; } int dinic(int s,int t){ int i,f,k,u,qin; int flow=0; while(bfs(s,t)){ memcpy(cur,head,sizeof(head)); u=s,qin=0; while(1){ if(u==t){ for(k=0,f=inf;k<qin;k++) if(edge[que[k]].f<f) f=edge[que[i=k]].f; for(k=0;k<qin;k++) edge[que[k]].f-=f,edge[que[k]^1].f+=f; flow+=f,u=edge[que[qin=i]].u; } for(i=cur[u];cur[u]!=-1;i=cur[u]=edge[cur[u]].next) if(edge[i].f>0 && lev[u]+1==lev[edge[i].v]) break; if(cur[u]!=-1) que[qin++]=cur[u],u=edge[cur[u]].v; else{ if(qin==0) break; lev[u]=-1,u=edge[que[--qin]].u; } } } return flow; } int main(){ int a[M],n,i,j,f[M],ans; while(scanf("%d",&n)!=-1){ ainit();ans=1; for(i=1,f[0]=0;i<=n;i++) f[i]=1; for(i=1;i<=n;i++){ scanf("%d",&a[i]); for(j=1;j<i;j++) if(a[j]<a[i] && f[j]>=f[i]) f[i]=f[j]+1; if(f[i]>ans) ans=f[i]; } for(i=1;i<=n;i++){ if(f[i]==1) addedge(0,i,1); if(f[i]==ans) addedge(i,n+1,1); } for(i=1;i<=n;i++) for(j=1;j<i;j++) if(a[i]>a[j] && f[i]==f[j]+1) addedge(j,i,1); printf("%d\n%d\n",ans,dinic(0,n+1)); if(ans==1){ printf("%d\n",n); continue; } for(i=0;i<p;i+=2) if(edge[i].u==0 || edge[i].v==n+1) edge[i].f=inf,edge[i^1].f=0; else edge[i].f=1,edge[i^1].f=0; printf("%d\n",dinic(0,n+1)); } return 0; }