zoukankan      html  css  js  c++  java
  • 3532: [Sdoi2014]Lis 最小字典序最小割

      

    3532: [Sdoi2014]Lis

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 865  Solved: 311
    [Submit][Status][Discuss]

    Description

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

    这题难点在如何求一组最小字典序最小的最小割。

    一条边是一种割集中的一条边当且仅当它在任何最大流方案中都是满流。

    即它当前满流且从这条边的出点到入点找不到增广路。

    当确定一条边必须在边集中后,从出点向S增广,从T向入点增广,再把容量清零,相当于把这条边删掉。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #define ll long long
    #define inf 0x3f3f3f3f
    #define N 1405
    #define M 1000005
    using namespace std;
    vector<int>ss;
    int head[N],ver[M],nxt[M],f[M],tot;
    void add(int a,int b,int c)
    {
    	tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;f[tot]=c;
    	tot++;nxt[tot]=head[b];head[b]=tot;ver[tot]=a;f[tot]=0;return ;
    }
    queue<int>q;int ch[N];
    int S,T;
    bool tell()
    {
    	memset(ch,-1,sizeof(ch));
    	q.push(S);ch[S]=0;
    	while(!q.empty())
    	{
    		int tmp=q.front();q.pop();
    		for(int i=head[tmp];i;i=nxt[i])
    		{
    			if(f[i]&&ch[ver[i]]==-1)
    			{
    				ch[ver[i]]=ch[tmp]+1;
    				q.push(ver[i]);
    			}
    		}
    	}
    	return ch[T]!=-1;
    }
    ll zeng(int a,int b)
    {
    	if(a==T)return b;
    	int r=0;
    	for(int i=head[a];i!=0&&b>r;i=nxt[i])
    	{
    		if(f[i]&&ch[ver[i]]==ch[a]+1)
    		{
    			int t=zeng(ver[i],min(f[i],b-r));
    			f[i]-=t;f[i^1]+=t;r+=t;
    		}
    	}
    	if(!r)ch[a]=-1;
    	return r;
    }
    ll dinic()
    {
    	ll r=0,t;
    	while(tell())
    	{
    		while(t=zeng(S,inf))
    		{
    			r+=t;
    		}
    	}
    	return r;
    }
    int n,a[N],b[N],c[N];
    int p[N],dp[N];
    bool cmp(int x,int y)
    {
    	return c[x]<c[y];
    }
    int main()
    {
    	int cas;
    	scanf("%d",&cas);
    	while(cas--)
    	{
    		memset(head,0,sizeof(head));
    		memset(dp,0,sizeof(dp));
    		ss.clear();
    		scanf("%d",&n);tot=1;// i i*2 i*2+1
    		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]),add(i,i+n,b[i]);
    		for(int i=1;i<=n;i++)p[i]=i;
    		sort(p+1,p+n+1,cmp);int mx=0;
    		for(int i=1;i<=n;i++)
    		{
    			dp[i]=1;
    			for(int j=1;j<i;j++)
    			{
    				if(a[i]>a[j])dp[i]=max(dp[i],dp[j]+1);
    			}
    			mx=max(mx,dp[i]);
    		}
    		S=0;T=2*n+1;
    		for(int i=1;i<=n;i++)if(dp[i]==mx)add(i+n,T,inf);
    		for(int i=1;i<=n;i++)if(dp[i]==1)add(S,i,inf);
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<i;j++)
    			{
    				if(a[i]>a[j]&&dp[i]==dp[j]+1)
    				{
    					add(j+n,i,inf);
    				}
    			}
    		}
    		ll ans1=dinic();
    		for(int i=1;i<=n;i++)
    		{
    			int x=p[i];
    			S=x;T=x+n;
    			if(f[x*2]||tell())continue;
    			S=x;T=0;dinic();
    			S=2*n+1;T=x+n;dinic();
    			ss.push_back(x);
    			f[x*2]=f[x*2+1]=0;
    		}
    		sort(ss.begin(),ss.end());
    		printf("%lld %d
    ",ans1,ss.size());
    		for(int i=0;i<ss.size();i++)
    		{
    			printf("%d%c",ss[i]," 
    "[i==ss.size()-1]);
    		}
    	}
    	return 0;
    }
    

      

     
     
  • 相关阅读:
    又是运行不到main的问题
    stlink问题
    AD7124踩过的坑
    stm32上调试AD5410
    linux读xml文件问题
    stm8问题记录
    430 仿真器 问题
    虚拟机VMware显示“内部错误”的解决方法
    VS2008 如何设置字体大小?
    Hyperledger Indy项目
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6688384.html
Copyright © 2011-2022 走看看