LOJ #2196「SDOI2014」LIS
直接退流复杂度好优越啊
题意
一段数列,每个点有点权$ A_i$,删除代价$ B_i$,附加属性$ C_i$
求最小代价使得$ LIS$长度发生变化,且输出一种$ C_i$字典序最小的方案
$ Solution$
首先可以求出以每个点结尾的$ LIS$长度数组$ f_i$
按照套路建图
$ i向i+n$连边权为删除代价的边
若$ f_i$=1则$ S向i$连边权为$ INF$的边
若$ f_i$=$ans$则 $i+n向T$连边权为$ INF$的边
然后最小割即是答案
跑一遍最大流即可
考虑输出方案
我们按$ C_i$从小到大枚举每条边,判断这条边是否是割边
若是则选它并删除这条边的贡献
删除之后不需要重新流一遍
只需要从$ i$向$ S$流一遍再从$T$向$ i+n$流一遍去掉贡献
最后再把边的流量上限改成$ 0$即可
复杂度可能是$ O(n^3)$的?
$ my \ code$
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #define INF 1000000000 #define M 1000010 #define rt register int #define ll long long using namespace std; inline ll read(){ ll x = 0; char zf = 1; char ch = getchar(); while (ch != '-' && !isdigit(ch)) ch = getchar(); if (ch == '-') zf = -1, ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ll y){write(y);putchar('\n');} int i,j,k,m,n,x,y,z,cnt,sum,S,T; int A[710],B[710],f[710]; int F[M],N[M],L[M],a[M],c[M],dis[M],cur[M],Gap[M]; void add(int x,int y,int z){ a[++k]=y;c[k]=z; if(!F[x])F[x]=k; else N[L[x]]=k; L[x]=k; } int q[M],h,t; bool BFS(int S,int T){ h=0;q[t=1]=S; memset(dis,10,4*sum+4);memcpy(cur,F,4*sum+4); dis[S]=0; while(h<t){ int x=q[++h]; for(rt i=F[x];i;i=N[i])if(c[i]&&dis[a[i]]>sum){ q[++t]=a[i]; dis[a[i]]=dis[x]+1; if(a[i]==T)return 1; } } return 0; } int dfs(int x,int y,int flow){ int used=0; if(x==y)return flow; for(rt i=cur[x];i;i=cur[x]=N[i])if(c[i]&&dis[x]+1==dis[a[i]]){ int v=dfs(a[i],y,min(flow-used,c[i])); if(!v)continue; c[i]-=v;c[i^1]+=v;used+=v; if(used>=flow)return used; } if(!--Gap[dis[x]])dis[S]=sum+1; ++Gap[++dis[S]]; return used; } int dinic(int S,int T){ int ans=0,now;Gap[0]=sum; while(BFS(S,T)){ memset(dis,0,sizeof(dis)); while(now=dfs(S,T,INF))ans+=now; } return ans; } struct node{ int x,val; bool operator <(const node s)const{ return val<s.val; } }C[705]; int ans[705],tot; int main(){ for(rt QAQ=read();QAQ;QAQ--){ for(rt i=1;i<=sum;i++)F[i]=0; for(rt i=1;i<=k;i++)L[i]=N[i]=0; n=read();k=1; for(rt i=1;i<=n;i++)A[i]=read(); for(rt i=1;i<=n;i++)B[i]=read(); for(rt i=1;i<=n;i++)C[i].val=read(),C[i].x=i; for(rt i=1;i<=n;i++)f[i]=1; for(rt i=2;i<=n;i++) for(rt j=1;j<i;j++)if(A[i]>A[j])f[i]=max(f[i],f[j]+1); int maxf=*max_element(f+1,f+n+1); for(rt i=1;i<=n;i++)add(i,i+n,B[i]),add(i+n,i,0); sort(C+1,C+n+1);S=n*2+1,sum=T=n*2+2; for(rt i=1;i<=n;i++) for(rt j=i+1;j<=n;j++)if(f[j]==f[i]+1)add(i+n,j,INF),add(j,i+n,0); for(rt i=1;i<=n;i++)if(f[i]==1)add(S,i,INF),add(i,S,0); for(rt i=1;i<=n;i++)if(f[i]==maxf)add(i+n,T,INF),add(T,i+n,0); write(dinic(S,T));putchar(' '); tot=0; for(rt i=1;i<=n;i++)if(!BFS(C[i].x,C[i].x+n)){ c[C[i].x<<1]=c[C[i].x<<1|1]=0; dinic(T,C[i].x+n);dinic(C[i].x,S); ans[++tot]=C[i].x; } sort(ans+1,ans+tot+1);writeln(tot); for(rt i=1;i<=tot;i++)write(ans[i]),putchar(' ');putchar('\n'); } return 0; }