LOJ #2196「SDOI2014」LIS

直接退流复杂度好优越啊

LOJ #2196


题意

一段数列,每个点有点权$ 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;
}

 

posted @ 2018-12-07 11:35  Kananix  阅读(204)  评论(0编辑  收藏  举报

Contact with me