题目:最长不下降子序列问题
思路:
第一问,
O
(
n
2
)
O(n^2)
O(n2)求LIS即可。
处理出
f
[
i
]
f[i]
f[i]表示以i开头的不下降子序列个数,得出答案记为k。
第二问,先拆点,把一个点
x
x
x拆成
(
x
,
0
)
(x,0)
(x,0)和
(
x
,
1
)
(x,1)
(x,1),并把两者连边。
设置一个原点S和汇点T。
把S和所有
f
[
i
]
=
=
1
f[i]==1
f[i]==1的点连边,把所有
f
[
i
]
=
=
k
f[i]==k
f[i]==k的点和T连边。
对于
f
[
j
]
=
f
[
i
]
+
1
,
j
<
i
f[j]=f[i]+1,j<i
f[j]=f[i]+1,j<i,且a[j]<=a[i],将
(
j
,
1
)
(j,1)
(j,1)和
(
i
,
0
)
(i,0)
(i,0)连边。
以上边权均为1,连边定义为从前者向后者引一条有向边。
第三问,只需在第二问的基础上,如果存在,将 [ S , ( 1 , 0 ) ] [S,(1,0)] [S,(1,0)], [ ( 1 , 0 ) , ( 1 , 1 ) ] [(1,0),(1,1)] [(1,0),(1,1)], [ ( n , 0 ) , ( n , 1 ) ] [(n,0),(n,1)] [(n,0),(n,1)], [ ( n , 1 ) , T ] [(n,1),T] [(n,1),T]这几条边权改为inf。
代码:
#include<bits/stdc++.h>
using namespace std;
struct Edge{
int u,v,w;
Edge(){}
Edge(int uu,int vv,int ww){u=uu,v=vv,w=ww;}
};
#define maxn 500000
#define read(x) scanf("%d",&x)
#define inf ((int)1e9)
int n;
int a[maxn+5];
int f[maxn+5];
Edge e[maxn+5];
int h[maxn+5],nxt[maxn+5],cnt=-1;
int d[maxn+5];
int cur[maxn+5];
void readin() {
read(n);
for(int i=1;i<=n;i++) read(a[i]);
}
int LIS() {
int s=0;
for(int i=n;i>=1;i--) {
for(int j=i;j<=n;j++) {
if(a[j]>=a[i]) f[i]=max(f[i],1+f[j]);
}
s=max(s,f[i]);
}
return s;
}
void add(int u,int v,int w) {
e[++cnt]=Edge(u,v,w);
nxt[cnt]=h[u];
h[u]=cnt;
}
void makeg(int k){
memset(nxt,-1,sizeof(nxt)),memset(h,-1,sizeof(h)),cnt=-1;
for(int i=1;i<=n;i++) if(f[i]==k) add(0,i,1),add(i,0,0);
for(int i=1;i<=n;i++) if(f[i]==1) add(n+i,2*n+1,1),add(2*n+1,n+i,0);
for(int i=1;i<=n;i++) add(i,n+i,1),add(n+i,i,0);
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(a[j]<=a[i]&&f[j]-f[i]==1) add(j+n,i,1),add(i,j+n,0);
}
void makeg2(int k) {
memset(nxt,-1,sizeof(nxt)),memset(h,-1,sizeof(h)),cnt=-1;
for(int i=2;i<=n;i++) if(f[i]==k) add(0,i,1),add(i,0,0);
if(f[1]==k) add(0,1,inf),add(1,0,0);
for(int i=1;i<n;i++) if(f[i]==1) add(n+i,2*n+1,1),add(2*n+1,n+i,0);
if(f[n]==1) add(2*n,2*n+1,inf),add(2*n+1,2*n,0);
for(int i=2;i<n;i++) add(i,n+i,1),add(n+i,i,0);
add(1,1+n,inf),add(1+n,1,0);
add(n,2*n,inf),add(2*n,n,0);
for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(a[j]<=a[i]&&f[j]-f[i]==1) add(j+n,i,1),add(i,j+n,0);
}
queue<int> que;
bool bfs() {
memset(d,0,sizeof(d));
d[0]=1;
que.push(0);
while(!que.empty()) {
int x=que.front();que.pop();
for(int i=h[x];~i;i=nxt[i]) {
Edge y=e[i];
if(y.w==0||d[y.v]) continue;
d[y.v]=d[x]+1;
que.push(y.v);
}
}
if(d[2*n+1]>0) return true;
return false;
}
int dfs(int x,int w) {
if(x==2*n+1) return w;
for(int& i=cur[x]; ~i;i=nxt[i]) {
Edge y=e[i];
if(d[y.v]-d[x]!=1||!y.w) continue;
int z=dfs(y.v,min(w,y.w));
if(z) {
e[i].w-=z;
e[i^1].w+=z;
return z;
}
}
return 0;
}
int dinic() {
int ans=0;
while(bfs()) {
for(int i=0;i<=2*n+1;i++) cur[i]=h[i];
while(int x=dfs(0,inf)) ans+=x;
}
return ans;
}
int main() {
readin();
int k=LIS();
printf("%d\n",k);
makeg(k);
int ans1=dinic();
makeg2(k);
int ans2=dinic();
printf("%d\n%d",ans1,ans2);
return 0;
}