DTOJ#4748. 钢镚

一共有 X + Y + Z X+Y+Z X+Y+Z 个人,每个人有 A i A_i Ai 个金钢镚, B i B_i Bi 个银钢镚, C i C_i Ci 个铜钢镚,你现在要从 X X X 个人那里拿走他们的金钢镚,从 Y Y Y 个人那里拿走他们的银钢镚,从 Z Z Z 个人那里拿走他们的铜钢镚。每个人被收且只被收了一次钢镚,那么你最多能拿到多少钢镚呢?

第一行三个正整数,分别为 X , Y , Z X,Y,Z X,Y,Z

之后 X + Y + Z X+Y+Z X+Y+Z 行,每行三个非负整数 A i , B i , C i A_i,B_i,C_i Ai,Bi,Ci

一行,表示最多能拿到的钢镚数目

样例输入1
1 2 1
2 4 4
3 2 1
7 6 7
5 2 3
样例输出1
18
样例输入2
6 2 4
33189 87907 277349742
71616 46764 575306520
8801 53151 327161251
58589 4337 796697686
66854 17565 289910583
50598 35195 478112689
13919 88414 103962455
7953 69657 699253752
44255 98144 468443709
2332 42580 752437097
39752 19060 845062869
60126 74101 382963164
样例输出2
3093929975

A i , B i , C i ≤ 1 0 9 A_i,B_i,C_i \le 10^9 Ai,Bi,Ci109

编号 X + Y + Z ≤ X+Y+Z \le X+Y+Z特殊性质
1 − 4 1-4 14 200000 200000 200000 Z = 0 Z=0 Z=0
5 − 8 5-8 58 1000 1000 1000
9 − 20 9-20 920 200000 200000 200000

noi2019 集训 5.6

①模拟费用流

#include<bits/stdc++.h>
#define N 200005
typedef long long ll;

using namespace std;
const ll inf=1e15;
inline int read(){
	int x=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	return x*f;
}
ll w[N][4],li[4],be[N];
priority_queue<pair<ll, int> > q[4][4];
int sz[4];
ll ans;
inline void ins(int x,int j){
	sz[j]++;be[x]=j;
	for(int k=1;k<=3;++k)if(k!=j){
		q[j][k].push(make_pair(w[x][k]-w[x][j],x));
	}
}
inline void del(int x,int j,int k){
	sz[j]--;be[x]=0;
	ins(x,k);
}
int main(){
//	freopen("gangbeng.in","r",stdin);
//	freopen("gangbeng.out","w",stdout);
  //  freopen("data.in","r",stdin);
  //  freopen("gangbeng.out","w",stdout);
	int x=read(),y=read(),z=read(),n=x+y+z;
	li[1]=x,li[2]=y,li[3]=z;
	for(int i=1;i<=n;++i)for(int j=1;j<=3;++j)w[i][j]=read();
	for(int i=1;i<=n;++i){
	    ll maxn=-inf,now[4]={-inf,-inf,-inf,-inf};int res=0,flag=1;
	    for(int j=1;j<=3;++j){
	    	for(int k=1;k<=3;++k)if(k!=j){
	    		while(!q[j][k].empty()&&be[q[j][k].top().second]!=j)q[j][k].pop();
	    	}
	    }
	    //cout<<1<<endl;
	    //cout<<i<<" "<<sz[1]<<" "<<sz[2]<<" "<<sz[3]<<endl;
		for(int j=1;j<=3;++j){
			if(!li[j])continue;
			if(sz[j]<li[j]){
				now[j]=w[i][j];
			}else{
				for(int k=1;k<=3;++k){
				    if(!li[k])continue;
					if(k==j)continue;
		    		res=1;while(res==j||res==k)++res;
					if(sz[k]<li[k]){
						//if(q[j][k].empty())cout<<i<<" "<<j<<" "<<k<<endl;
						now[j]=max(now[j],w[i][j]+q[j][k].top().first);
					}else{
						//if(q[k][res].empty())cout<<i<<" "<<j<<" "<<k<<" "<<res<<endl;
						if(li[res]){
						    now[j]=max(now[j],w[i][j]+q[j][k].top().first+q[k][res].top().first);
					    }
					}
				}
			}
			maxn=max(maxn,now[j]);
		}
		now[1]=now[2]=now[3]=-inf;
		for(int j=1;j<=3;++j){
			if(!li[j])continue;
			if(flag==0)break;
			if(sz[j]<li[j]){
				now[j]=w[i][j];
				if(now[j]==maxn&&flag){
					flag=0;ins(i,j);
				}
			}else{
				for(int k=1;k<=3;++k){
					if(!li[k])continue;
					if(k==j)continue;
					res=1;while(res==j||res==k)++res;
					if(sz[k]<li[k]){
						now[j]=max(now[j],w[i][j]+q[j][k].top().first);
						if(now[j]==maxn&&flag){
							flag=0;del(q[j][k].top().second,j,k);
							ins(i,j);
						}
							
					}else{
						if(li[res]){
						    now[j]=max(now[j],w[i][j]+q[j][k].top().first+q[k][res].top().first);
					        if(now[j]==maxn&&flag){
					    	    flag=0;int x=q[j][k].top().second,y=q[k][res].top().second;
					    	    del(x,j,k);del(y,k,res);ins(i,j);
					        }
					    }
					}
				}
			}
		}
		ans=ans+maxn;
	}
	printf("%lld\n",ans);
	return 0;
}/*
1 2 1
2 4 4
3 2 1
7 6 7
5 2 3
*/

②简单贪心

#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
struct ppap
{
	long long a,b,c;
	bool operator < (const ppap &A) const
	{
		return a-b<A.a-A.b;
	}
}b[100010];
priority_queue<long long,vector<long long>,greater<long long> > q;
long long x,y,z,n,S,sum,ans,s[100010];
int main()
{
	scanf("%lld%lld%lld",&x,&y,&z),n=x+y+z;
	for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&b[i].a,&b[i].b,&b[i].c),S+=b[i].c;
	sort(b+1,b+1+n);
	for(int i=1;i<=y;i++) sum+=b[i].b-b[i].c,q.push(b[i].b-b[i].c);
	for(int i=y+1;i<=n-x+1;i++) s[i]=sum,sum+=b[i].b-b[i].c,q.push(b[i].b-b[i].c),sum-=q.top(),q.pop();
	while(!q.empty()) q.pop();
	sum=0;
	for(int i=n;i>n-x;i--) sum+=b[i].a-b[i].c,q.push(b[i].a-b[i].c);
	for(int i=n-x;i>=y;i--) ans=max(ans,S+s[i+1]+sum),sum+=b[i].a-b[i].c,q.push(b[i].a-b[i].c),sum-=q.top(),q.pop();
	printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值