题目:最长不下降子序列问题
思路:
第一问, 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
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;
}