题意:给你一个序列,求不严格上升lcs长度/最多有几个没有重复元素的lcs/如果x1和xn可以多次出现,求最多有几个lcs?n<=500.
标程:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 const int N=510; 7 const int inf=0x3f3f3f3f; 8 queue<int> q; 9 int cnt=1,dis[N],S,T,x1,xn,a[N],f[N],Head[N],ans,head[N],n,Max,tmp,ans1; 10 struct node{int to,next,w;}num[N*N*2]; 11 void add(int x,int y,int w) 12 {num[++cnt].to=y;num[cnt].next=head[x];num[cnt].w=w;head[x]=cnt; 13 num[++cnt].to=x;num[cnt].next=head[y];num[cnt].w=0;head[y]=cnt;} 14 void build() 15 { 16 for (int i=1;i<=n;i++) 17 for (int j=i+1;j<=n;j++) 18 if (a[i]<=a[j]&&f[i]+1==f[j]) add((i==1)?x1:((i==n)?xn:i),j,1); 19 for (int i=1;i<=n;i++) 20 { 21 if (f[i]==1) add(S,i,1); 22 if (f[i]==Max) add((i==1)?x1:((i==n)?xn:i),T,1); 23 } 24 add(1,x1,1);add(n,xn,1); 25 } 26 bool bfs() 27 { 28 memset(dis,0,sizeof(dis));dis[S]=1; 29 q.push(S); 30 while (!q.empty()) 31 { 32 int now=q.front();q.pop(); 33 for (int i=head[now];i;i=num[i].next) 34 if (num[i].w&&!dis[num[i].to]) 35 dis[num[i].to]=dis[now]+1,q.push(num[i].to); 36 } 37 return dis[T]!=0; 38 } 39 int dfs(int x,int mm) 40 { 41 int tmp=mm; 42 if (x==T) return mm; 43 for (int &i=Head[x];i&&tmp;i=num[i].next) 44 if (num[i].w&&dis[num[i].to]==dis[x]+1) 45 { 46 int t=dfs(num[i].to,min(num[i].w,tmp)); 47 tmp-=t;num[i].w-=t;num[i^1].w+=t; 48 } 49 return mm-tmp; 50 } 51 void dinic() 52 { 53 while (bfs()) 54 { 55 memcpy(Head,head,sizeof(head)); 56 while (tmp=dfs(S,inf)) ans+=tmp; 57 } 58 } 59 int main() 60 { 61 scanf("%d",&n);S=n+1;T=S+1;x1=T+1;xn=x1+1; 62 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 63 f[1]=1; 64 for (int i=2;i<=n;i++) 65 { 66 for (int j=1;j<i;j++) 67 if (a[i]>=a[j]) f[i]=max(f[i],f[j]); 68 f[i]++; 69 } 70 for (int i=1;i<=n;i++) Max=max(Max,f[i]); 71 printf("%d ",Max); 72 build();dinic(); 73 printf("%d ",ans);ans1=ans; 74 add(1,x1,inf);add(n,xn,inf); 75 for (int i=1;i<=n;i++) 76 { 77 if (f[i]==1) add(S,i,inf); 78 if (f[i]==Max) add((i==1)?x1:((i==n)?xn:i),T,inf); 79 } 80 dinic(); 81 if (Max==1) printf("%d ",ans1);else printf("%d ",ans); 82 return 0; 83 }
易错点:1.需要特判lcs=1时询问3的答案和询问2是一样的。不然会错。
题解:网络流+拆点
第一问直接dp。
第二问对于i<j&&a[i]<=a[j]&&f[i]+1==f[j]的(i,j)连容量为1的边,f[i]=1向S连边,f[i]=Max向T连边。跑最大流。
第三问可以直接在第二问的残图上跑,对于x1和xn点拆点(可以在第二问建图时就拆好),设置点流量为inf。同时对于所有向源汇连的边都设为inf。