Scx117
只一眼,便辽阔了时间。

题意:给你一个序列,求不严格上升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\n",Max);
72     build();dinic();
73     printf("%d\n",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\n",ans1);else printf("%d\n",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。

 

posted on 2018-04-05 10:47  Scx117  阅读(156)  评论(0编辑  收藏  举报