zoukankan      html  css  js  c++  java
  • [BZOJ]3532: [Sdoi2014]Lis

    Time Limit: 10 Sec  Memory Limit: 512 MB

    Description

      给定序列A,序列中的每一项Ai有删除代价Bi和附加属性Ci。请删除若干项,使得4的最长上升子序列长度减少至少1,且付出的代价之和最小,并输出方案。

      如果有多种方案,请输出将删去项的附加属性排序之后,字典序最小的一种。

    Input

      输入包含多组数据。
      输入的第一行包含整数T,表示数据组数。接下来4*T行描述每组数据。
      每组数据的第一行包含一个整数N,表示A的项数,接下来三行,每行N个整数A1..An,B1.,Bn,C1..Cn,满足1 < =Ai,Bi,Ci < =10^9,且Ci两两不同。

    Output

      对每组数据,输出两行。第一行包含两个整数S,M,依次表示删去项的代价和与数量;接下来一行M个整数,表示删去项在4中的的位置,按升序输出。

    Sample Input

      1
      6
      3 4 4 2 2 3
      2 1 1 1 1 2
      6 5 4 3 2 1

    Sample Output

      4 3
      2 3 6
      解释:删去(A2,43,A6),(A1,A6),(A2,43,44,A5)等都是合法的方案,但
      {A2,43,A6)对应的C值的字典序最小。

    HINT

      1 < =N < =700     T < =5

    Solution

      先从后往前DP求出f[i]表示以a[i]开头的最长上升子序列长度。根据DP转移路径建出最小割模型:若f[i]=A的最长上升子序列长度,S到i连INF;若f[i]=1,i到T连INF;若j能转移到i,i向j连INF,每个点再拆成两个点,边权为bi。考虑如何求出字典序最小的最小割,按ci从小到大贪心,如果i拆出的边能作为割边,即拆出的两个点只走未满流边不能互相到达,那么选进答案,并且我们要消除这条边对之后的影响,就让入点到S跑一遍最大流,T到出点也跑一遍最大流,这样流到这条边的流量就都被退了回去。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
        return x;
    }
    #define MN 700
    #define MV 1400
    #define ME 250000
    #define INF 0x7FFFFFFF
    struct edge{int nx,t,w;}e[ME*2+5];
    int A[MN+5],B[MN+5],C[MN+5],f[MN+5],p[MN+5],as[MN+5],an;
    int S,T,h[MV+5],en,d[MV+5],q[MV+5],qn,c[MV+5];
    bool cmp(int a,int b){return C[a]<C[b];}
    inline void ins(int x,int y,int w)
    {
        e[++en]=(edge){h[x],y,w};h[x]=en;
        e[++en]=(edge){h[y],x,0};h[y]=en;
    }
    bool bfs()
    {
        int i,j;
        memset(d,0,sizeof(d));
        for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx)
            if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1;
        return d[T];
    }
    int dfs(int x,int r)
    {
        if(x==T)return r;
        int k,u=0;
        for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[e[i].t]==d[x]+1)
        {
            k=dfs(e[i].t,min(e[i].w,r-u));
            u+=k;e[i].w-=k;e[i^1].w+=k;
            if(u==r)return u;
        }
        return d[x]=0,u;
    }
    int main()
    {
        int t=read(),n,i,j,ans;
        while(t--)
        {
            n=read();
            for(i=1;i<=n;++i)A[i]=read();
            for(i=1;i<=n;++i)B[i]=read();
            for(i=1;i<=n;++i)C[i]=read();
            for(i=n;i>=0;++f[i--])
                for(f[i]=0,j=n;j>i;--j)if(A[j]>A[i])f[i]=max(f[i],f[j]);
            S=MV+1;T=MV+2;memset(h,0,sizeof(h));en=1;
            for(i=1;i<=n;p[i]=i,++i)
            {
                ins(i,i+n,B[i]);
                if(f[i]+1==f[0])ins(S,i,INF);
                if(f[i]==1)ins(i+n,T,INF);
                for(j=i;++j<=n;)if(A[j]>A[i]&&f[i]==f[j]+1)ins(i+n,j,INF);
            }
            for(ans=0;bfs();)ans+=dfs(S,INF);
            sort(p+1,p+n+1,cmp);
            for(an=0,i=1;i<=n;++i)
            {
                if(S=p[i],T=S+n,bfs())continue;
                as[++an]=p[i];
                for(T=MV+1;bfs();)dfs(S,INF);
                for(T=p[i]+n,S=MV+2;bfs();)dfs(S,INF);
            }
            sort(as+1,as+an+1);
            printf("%d %d
    ",ans,an);
            for(i=1;i<=an;++i)printf("%d%c",as[i],i<an?' ':'
    ');
        }
    }
  • 相关阅读:
    腾讯云短信接口完成验证码功能
    git使用的简要介绍
    drf分页组件补充
    drf中的jwt使用与手动签发效验
    django的认证演变过程分析
    drf三大认证补充
    drf三大认证
    IO事件
    配置Java环境变量
    各种O
  • 原文地址:https://www.cnblogs.com/ditoly/p/BZOJ3532.html
Copyright © 2011-2022 走看看