• luogu P5470 [NOI2019]序列 dp 贪心 费用流 模拟费用流


    LINK:序列

    考虑前20分 容易想到爆搜。

    考虑dp 容易设(f_{i,j,k,l})表示前i个位置 选了j对 且此时A选择了k个 B选择了l个的最大值.期望得分28.

    code
    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cctype>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007ll
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-4
    #define sq sqrt
    #define F first
    using namespace std;
    char *fs,*ft,buf[1<<15];
    inline char gc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
    	RE int x=0,f=1;RE char ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    	return x*f;
    
    }
    const int MAXN=32;
    int T,n,K,L;
    int a[MAXN],b[MAXN];
    ll f[MAXN][MAXN][MAXN][MAXN];
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(T);
    	while(T--)
    	{
    		memset(f,0xcf,sizeof(f));
    		get(n);get(K);get(L);
    		rep(1,n,i)get(a[i]);
    		rep(1,n,i)get(b[i]);
    		f[0][0][0][0]=0;
    		rep(1,n,i)
    		{
    			int cc=min(i-1,L);
    			rep(0,cc,j)
    			{
    				int ww=min(i-1,K);
    				rep(0,ww,l)rep(0,ww,r)
    				{
    					if(l+1<=K&&r+1<=K&&j+1<=L)f[i][j+1][l+1][r+1]=max(f[i-1][j][l][r]+a[i]+b[i],f[i][j+1][l+1][r+1]);
    					if(l+1<=K&&r+1<=K)f[i][j][l+1][r+1]=max(f[i-1][j][l][r]+a[i]+b[i],f[i][j][l+1][r+1]);
    					if(l+1<=K)f[i][j][l+1][r]=max(f[i-1][j][l][r]+a[i],f[i][j][l+1][r]);
    					if(r+1<=K)f[i][j][l][r+1]=max(f[i-1][j][l][r]+b[i],f[i][j][l][r+1]);
    					f[i][j][l][r]=max(f[i][j][l][r],f[i-1][j][l][r]);
    				}
    			}
    		}
    		putl(f[n][L][K][K]);
    	}
    	return 0;
    }
    

    容易发现这可以贪心 考虑费用流.遗憾的是 考场上我建了2h的图没建出来。

    最近 我又建了1h图 还是没有什么进展 看完题解的建图恍然大悟.

    我一直考虑把限制少的先建立出来 把限制多的放后边加边来进行限制。

    其实并非如此.先考虑 将限制多的先建立出来.

    即先限流L 然后流向每个i点流量费用((1,A[i])) 然后 i+n((1,B[i])) 然后 i向i+n连边。

    接下来处理那些随便流的。i连向一个公共点cc 然限流 cc-zz (K-L,0) zz连向i+n的那些点即可.

    期望的分64?实际得分48.

    code
    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cctype>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 10000000000000000ll
    #define inf 1000000000
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007ll
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-4
    #define sq sqrt
    #define S second
    #define F first
    using namespace std;
    char *fs,*ft,buf[1<<15];
    inline char gc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
    	RE int x=0,f=1;RE char ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    	return x*f;
    
    }
    const int MAXN=200010,N=MAXN<<1,maxn=MAXN*5<<1;
    int n,m,T,TT,zz,cc,S,SS,K,L,len;
    int a[MAXN],b[MAXN],in[N],vis[N],pre[N];ll dis[N],ans;
    int lin[N],ver[maxn],e[maxn],e1[maxn],nex[maxn],q[maxn<<1];
    inline void add(int x,int y,int z,int z1)
    {
    	ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;e1[len]=z1;
    	ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;e1[len]=-z1;
    }
    inline bool spfa()
    {
    	rep(1,T,i)dis[i]=-INF;
    	dis[S]=0;in[S]=inf;int l=0,r;
    	q[r=1]=S;vis[S]=1;
    	//cout<<l<<endl;
    	while(++l<=r)
    	{
    		int x=q[l];vis[x]=0;
    		go(x)
    		{
    			if(!e[i])continue;
    			//cout<<tn<<endl;
    			if(dis[tn]<dis[x]+e1[i])
    			{
    				dis[tn]=dis[x]+e1[i];
    				if(!vis[tn])q[++r]=tn,vis[tn]=1;
    				in[tn]=min(in[x],e[i]);
    				pre[tn]=i;
    			}
    		}
    	}
    	//cout<<dis[T]<<endl;
    	return dis[T]!=-INF;
    }
    inline void EK()
    {
    	ans=0;
    	//cout<<1<<endl;
    	while(spfa())
    	{
    		int x=T,i=pre[x];
    		ans+=dis[T]*in[T];
    		while(x!=S)
    		{
    			e[i]-=in[T];
    			e[i^1]+=in[T];
    			x=ver[i^1];i=pre[x];
    		}
    	}
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(TT);
    	while(TT--)
    	{
    		rep(1,T,i)lin[i]=0;len=1;
    		get(n);get(K);get(L);
    		rep(1,n,i)get(a[i]);
    		rep(1,n,i)get(b[i]);
    		zz=n<<1|1;cc=zz+1;S=cc+1;SS=S+1;T=SS+1;
    		add(S,SS,K,0);
    		add(zz,cc,K-L,0);
    		rep(1,n,i)
    		{
    			add(i,i+n,1,0);
    			add(i,zz,1,0);
    			add(SS,i,1,a[i]);
    			add(cc,i+n,1,0);
    			add(i+n,T,1,b[i]);
    		}
    		//cout<<len<<endl;
    		EK();putl(ans);
    	}
    	return 0;
    }
    

    考虑正解 费用流是正确的 不过复杂度太高了 没有保证.

    我们可以进行模拟费用流来将复杂度降下来。

    所以操作都模拟费用流时 优先跑增广路的权值最大的即可.

    其中有些细节:因为退流的操作很难模拟出来,所以我们考虑当退流的时候 其实是选择一个和其匹配的点.

    综上 我们这个模拟费用流不退流 每个被选择的数字都是最终的答案的一部分.

    操作:显然应该先选出K-L的自由流.

    然后考虑三种情况 一种是a[x]+b[x] 一种是给已经选了A[x]的但没有选B[x]的配一个B[x]以及剩下的A中的最大值.

    还有一种和前者相反 讨论清楚 开堆模拟即可.

    容易证明复杂度为(nlogn)

    code
    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cctype>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 10000000000000000ll
    #define inf 1000000000
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007ll
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-4
    #define sq sqrt
    #define S second
    #define F first
    using namespace std;
    char *fs,*ft,buf[1<<15];
    inline char gc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
    	RE int x=0,f=1;RE char ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    	return x*f;
    }
    const int MAXN=200010,N=MAXN<<1,maxn=MAXN*5<<1;
    int n,m,K,L,T;ll ans=0;
    int a[MAXN],b[MAXN],id[MAXN],s[MAXN];
    struct A{int id;inline bool friend operator <(A x,A y){return a[x.id]<a[y.id];}}w1;
    struct B{int id;inline bool friend operator <(B x,B y){return b[x.id]<b[y.id];}}w2;
    struct AB{int id;inline bool friend operator <(AB x,AB y){return a[x.id]+b[x.id]<b[y.id]+a[y.id];}}w3;
    priority_queue<A>H1,F1;
    priority_queue<B>H2,F2;
    priority_queue<AB>H3;
    inline int cmpa(int x,int y){return a[x]>a[y];}
    inline int cmpb(int x,int y){return b[x]>b[y];}
    inline void solve(int m)
    {
    	rep(1,n,i)id[i]=i;ans=0;
    	sort(id+1,id+1+n,cmpa);rep(1,m,i)ans+=a[id[i]],s[id[i]]=1;
    	sort(id+1,id+1+n,cmpb);rep(1,m,i)ans+=b[id[i]],s[id[i]]|=2;
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(T);
    	while(T--)
    	{
    		get(n);get(K);get(L);
    		rep(1,n,i)get(a[i]),s[i]=0;
    		rep(1,n,i)get(b[i]);
    		while(H1.size())H1.pop();
    		while(H2.size())H2.pop();
    		while(H3.size())H3.pop();
    		while(F1.size())F1.pop();
    		while(F2.size())F2.pop();
    		solve(K-L);
    		int res=0;
    		rep(1,n,i)
    		{
    			if(s[i]==3){++res;continue;}
    			if(!s[i])
    			{
    				w1.id=i;H1.push(w1);
    				w2.id=i;H2.push(w2);
    				w3.id=i;H3.push(w3);
    			}
    			if(s[i]==1)w2.id=i,H2.push(w2),F2.push(w2);
    			if(s[i]==2)w1.id=i,H1.push(w1),F1.push(w1);
    		}
    		int id1,id2,v1,v2,v3,c1,c2,mx;
    		while(L--)
    		{
    			while(H1.size()&&(s[H1.top().id]&1))H1.pop();
    			while(F1.size()&&(s[F1.top().id]&1))F1.pop();
    			while(H2.size()&&(s[H2.top().id]&2))H2.pop();
    			while(F2.size()&&(s[F2.top().id]&2))F2.pop();	
    			while(H3.size()&&s[H3.top().id])H3.pop();
    			if(res)
    			{
    				--res;
    				id1=H1.top().id,id2=H2.top().id;
    				ans+=a[id1];ans+=b[id2];
    				s[id1]|=1;s[id2]|=2;
    				if(id1==id2){++res;continue;}
    				if(s[id1]==3)++res;
    				if(s[id2]==3)++res;
    				if(s[id1]==1)w2.id=id1,F2.push(w2);
    				if(s[id2]==2)w1.id=id2,F1.push(w1);
    				continue;
    			}
    			v1=0,v2=0,v3=0;
    			if(F1.size()){id2=H2.top().id;v1=a[F1.top().id]+b[id2],c1=id2==1?1:0;}	
    			if(F2.size()){id1=H1.top().id;v2=a[id1]+b[F2.top().id],c2=id1==2?1:0;}
    			if(H3.size()){id1=H3.top().id;v3=a[id1]+b[id1];}
    			mx=max(max(v1,v2),v3);
    			if(v1==v2&&v2==mx)
    			{
    				if(c1>=c2)
    				{
    					id2=H2.top().id;id1=F1.top().id;
    					ans+=a[id1]+b[id2];
    					s[id1]|=1;s[id2]|=2;
    					if(s[id2]==3)++res;
    					else w1.id=id2,F1.push(w1);
    				}
    				else
    				{
    					id1=H1.top().id;id2=F2.top().id;
    					ans+=a[id1]+b[id2];
    					s[id1]|=1;s[id2]|=2;
    					if(s[id1]==3)++res;
    					else w2.id=id1,F2.push(w2);
    				}
    				continue;
    			}
    			if(v1==mx)
    			{
    				id2=H2.top().id;id1=F1.top().id;
    				ans+=a[id1]+b[id2];
    				s[id1]|=1;s[id2]|=2;
    				if(s[id2]==3)++res;
    				else w1.id=id2,F1.push(w1);
    				continue;
    			}
    			if(v2==mx)
    			{
    				id1=H1.top().id;id2=F2.top().id;
    				ans+=a[id1]+b[id2];
    				s[id1]|=1;s[id2]|=2;
    				if(s[id1]==3)++res;
    				else w2.id=id1,F2.push(w2);
    				continue;
    			}
    			if(mx==v3)
    			{
    				id1=H3.top().id;
    				s[id1]=3;ans+=mx;
    				continue;
    			}
    		}
    		putl(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Saltstack module gem 详解
    Saltstack module freezer 详解
    Saltstack module firewalld 详解
    Saltstack module file 详解
    Saltstack module event 详解
    Saltstack module etcd 详解
    Saltstack module environ 详解
    Saltstack module drbd 详解
    Saltstack module dnsutil 详解
    获取主页_剥离百度
  • 原文地址:https://www.cnblogs.com/chdy/p/13369364.html
Copyright © 2020-2023  润新知