• BZOJ 3532: [Sdoi2014]Lis


    3532: [Sdoi2014]Lis

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 758  Solved: 284
    [Submit][Status][Discuss]

    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

    Source

    Round 1 Day 2

    分析:

    考虑如果没有字典序的限制,那么就是一个最小割...

    我们考虑$dp$的过程,就是一张有向无环图,起点就是$f[0]=0$,终点就是答案为最长上升子序列的位置,但是有很多所以我们建一个超级汇点,对于所有的$i<j$,$a[i]<a[j]$,$f[j]=f[i]+1$的点对都要连边,然后求出最小割就是最小的代价...

    现在考虑字典序最小的情况,首先我们先随便求出一个最小割,然后考虑什么样的边是割边,首先必须满流,这是首要条件,如果把这条边断掉,那么这条边所在的这条路径就没有必要再选择另一条边了...所以如果我们选择了一条边$<u,v>$,我们就把$S-->u$的流和$v-->T$的流退掉,这样就一定不会选择这条路径上的其他边了,现在要求字典序最小,所以我们从小到大枚举边,然后判断这条边是否是割边:满流并且不存在增广路径,如果是就断掉这条边,然后退流...

    貌似多$case$记得清数组什么的,然后就是行末不要加空格...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    //by NeighThorn
    #define inf 0x3f3f3f3f
    using namespace std;
     
    const int maxn=2000+5,maxm=1000000+5;
     
    int n,cas,cnt,Max,a[maxn],b[maxn],dp[maxn];
    int S,T,hd[maxn],fl[maxm],to[maxm],nxt[maxm],pos[maxn];
     
    vector<int> ans;
     
    struct M{
        int l,id;
        friend bool operator < (M a,M b){
            return a.l<b.l;
        }
    }c[maxn];
     
    inline void add(int x,int y,int s){
        fl[cnt]=s;to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
        fl[cnt]=0;to[cnt]=x;nxt[cnt]=hd[y];hd[y]=cnt++; 
    }
     
    inline bool bfs(int S,int T){
        memset(pos,-1,sizeof(pos));
        int head=0,tail=0,q[maxn];
        q[0]=S;pos[S]=0;
        while(head<=tail){
            int top=q[head++];
            for(int i=hd[top];i!=-1;i=nxt[i])
                if(pos[to[i]]==-1&&fl[i])
                    pos[to[i]]=pos[top]+1,q[++tail]=to[i];
        }
        return pos[T]!=-1;
    }
     
    inline long long find(int v,int f,int S,int T){
        if(v==T)
            return f;
        int res=0,t;
        for(int i=hd[v];i!=-1&&f>res;i=nxt[i])
            if(pos[to[i]]==pos[v]+1&&fl[i])
                t=find(to[i],min(f-res,fl[i]),S,T),fl[i]-=t,fl[i^1]+=t,res+=t;
        if(!res) pos[v]=-1;
        return res;
    }
     
    inline long long dinic(int S,int T){
        long long res=0,t;
        while(bfs(S,T)){
            while(t=find(S,inf,S,T))
                res+=t;
        }
        return res;
    }
     
    #define f dp
     
    signed main(void){
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
        scanf("%d",&cas);
        while(cas--){
            memset(f,0,sizeof(f));
            memset(hd,-1,sizeof(hd));
            Max=0;ans.clear();
            scanf("%d",&n);f[0]=0;cnt=0;S=2*n+1,T=2*n+2;
            for(int i=1;i<=n;i++) scanf("%d",&a[i]);
            for(int i=1;i<=n;i++) scanf("%d",&b[i]);
            for(int i=1;i<=n;i++) scanf("%d",&c[i].l),c[i].id=i;
            for(int i=1;i<=n;i++)
                for(int j=0;j<i;j++)
                    if(a[j]<a[i])
                        f[i]=max(f[i],f[j]+1);
            for(int i=1;i<=n;i++) Max=max(Max,f[i]);
            for(int i=1;i<=n;i++) add(i,n+i,b[i]);
            for(int i=1;i<=n;i++) if(Max==f[i]) add(i+n,T,inf);
            for(int i=1;i<=n;i++) if(f[i]==1) add(S,i,inf);
            for(int i=1;i<=n;i++)
                for(int j=1;j<i;j++)
                    if(f[i]==f[j]+1&&a[i]>a[j])
                        add(j+n,i,inf);
            long long mincost=dinic(S,T);sort(c+1,c+n+1);
            for(int i=1,x;i<=n;i++){
                x=c[i].id;
                if(fl[(x-1)*2]||bfs(x,x+n)) continue;
                ans.push_back(x);
                dinic(T,x+n),dinic(x,S);
                fl[(x-1)*2]=fl[(x-1)*2^1]=0;
            }
            sort(ans.begin(),ans.end());printf("%lld %d
    ",mincost,ans.size());
            for(int i=0;i<ans.size();i++) printf("%d%c",ans[i],(i==ans.size()- 1)?'
    ':' ');
        }
        return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    字符,字节和编码
    Linux网络参数和ifconfig
    默认网关 网关 子网掩码 广播地址
    S.M.A.R.T.记录几块ssd硬盘
    linux 别名
    echo 输出颜色
    Linux:echo命令详解
    centos下安装mongodb 通过shell脚本
    linux查看登录用户
    linux wget指定下载目录和重命名
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6612979.html
Copyright © 2020-2023  润新知