Three Bags CodeForces - 1467C (贪心)

题目链接

题意:给定三个背包,各自装有n1 n2 n3个数,每次操作从任意两个背包A B分别选出任意一个数a b,然后丢掉b ,把a替换成a-b 。 问重复操作下去最后剩下的数最大可以是多少。
(1<=n<=3e5)

分析:我们用A B C表示3个背包,min(B)<min(A) 且 min(C)<min(A)
假设最终的数是在A中。

一个数从初始背包转移出去,当且仅当它转移次数为偶数的时候才能对答案有正贡献。比如B中的某个数b[i],要产生正贡献比如和C中某个数结合,然后转移进A 。

于是我们想到一种贪心策略:
找出B C中各自最小的数minb ,minc 。
B中其他数与minc结合然后进入A ,
C中其他数与minb结合进入A ,
A中任意保留一个数a,其他的数都与minc/minb结合再与a结合,作正贡献。
这样最终只有minb、minc这两个数作了负贡献 。
答案就是allsum-2*(minb+minc)。

这种策略让B C两个集合的各自最小值作了负贡献,
另外我们还可以只让一个集合作负贡献 ,B中每个数都视为为C的中转站,
那么最终只有B集合全部的数作负贡献 。
答案就是allsum-2*sum(B)

两种策略取最优。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int maxn = 3e5+5;
const int mx = 40;
const int mod = 1e9+5;
const ll inf = 34359738370;
const int INF = 1e9+5;
//给定3个允许有重复元素的背包 装有整数 最大1e9
//每次操作可以任选背包1 2 各取一个数a b  丢弃1的a 2的b变成b-a
//最终只留下一个数  问最大能是多少

//3个集合初始都是非空集合 一个数进入其他背包偶数次才能有正贡献
//两种贪心策略
//1、取来自2个集合的最小的数  作为中转站  其余数和他们结合 然后再进入最终的背包
//答案就是其余数之和-这两个来自不同集合的最小的数
//2、舍弃一个集合作为中转站  答案是其余两个集合之和-和最小的集合的和
int n[4];
ll sum[4],mmin[4];
int main()
{
    mmin[1]=mmin[2]=mmin[3]=inf;
    for(int i=1;i<=3;i++) scanf("%d",n+i);
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=n[i];j++)
        {
            ll t;scanf("%I64d",&t);
            mmin[i]=min(mmin[i],t);
            sum[i]+=t;
        }
    }
    sum[0]=sum[1]+sum[2]+sum[3];//sum[0]为所有数的和
    ll ans=sum[0]-2*min(min(sum[1],sum[2]),sum[3]);//策略2  和最小的集合作负贡献
    ll mn2=mmin[1]+mmin[2]+mmin[3]-max(max(mmin[1],mmin[2]),mmin[3]);//最小的2个min之和
    ans=max(ans,sum[0]-2*mn2);//策略1
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值