题意:
x+y+z个人,每人有a,b,c三种硬币若干个,只能从每个人手上拿一种硬币,其中能拿a种硬币最多x个人,b种y人, c种z人,问最多能拿几个硬币。
解题思路:
先对每个人按a-b的大小排序,这样的话,选择a的x人一定都在选择b的y人右边,假设存在选择a的人在选择b的人左边,那么原先拿a的拿b,原先拿b的拿a,获得的金币数量要比原先多。
现在可以枚举下,y人是在前k人中选取,而x人是在n-k人中选取,枚举下k,算出分别获得多少a,b的金币即可。这个过程要用一下优先队列维护一下金币数量。
对于c的话,我们可以让b-c,a-c,最后再统一加上c的总和,这样就可以避免考虑c了。
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=1e5+5;
struct node
{
LL a, b, c;
bool operator <(const node & A) const
{
return (a-b)<A.a-A.b;
}
}p[maxn];
LL lef[maxn];
priority_queue<LL, vector<LL>, greater<LL> >q;
int main()
{
int x, y, z;
cin>>x>>y>>z;
int i, j, n=x+y+z;
LL base=0;
for(i=1; i<=n; i++)
{
scanf("%lld%lld%lld", &p[i].a, &p[i].b, &p[i].c);
base+=p[i].c;
}
sort(p+1, p+1+n);
LL ans=0, sum=0;
for(i=1; i<=y; i++)
{
sum+=p[i].b-p[i].c;
q.push(p[i].b-p[i].c);
}
for(i=y+1; i<=n-x+1; i++)
{
lef[i]=sum;
sum+=p[i].b-p[i].c;
q.push(p[i].b-p[i].c);
sum-=q.top();
q.pop();
}
while(q.empty()==0)q.pop();
sum=0;
for(i=n; i>=n-x+1; i--)
{
sum+=p[i].a-p[i].c;
q.push(p[i].a-p[i].c);
}
for(; i>=y; i--)
{
ans=max(ans, base+lef[i+1]+sum);
// printf("%d %lld %lld %lld\n", i, base, lef[i+1], sum);
sum+=p[i].a-p[i].c;
q.push(p[i].a-p[i].c);
sum-=q.top();
q.pop();
}
printf("%lld\n", ans);
}