Description
有X+Y+Z个人,每个人有一定的金、银、铜币,你可以向X个人要金币,向
Solution
按金币减去银币的数量从小到大排序:
在这个顺序下,最佳方案中所有给予金币的人都在给予银币的人的右边。(想一想,为什么)
存在整数K使得:左边的K个人中,有Y个给银币的人,(K-Y)个给铜币的人;其余的人中有X个给金币的人和(Y+Z-K)个给铜币的人。
我们假设每个人都没有铜币,使金币、银币的数量都减去铜币的数量,并在最终的答案中加上铜币数量。
然后我们就可以求出左边K个人的银币中最大的Y个,其余右边的人的金币中最大的X个,用堆维护即可。
Code
我已经成为缩行大师了?
//Author: Hany01
//Copyright 2017 (C) Hany01
#include<bits/stdc++.h>
#define For(i , j , k) for (register int i = (j) , i##_end_ = (k) ; i <= i##_end_ ; ++ i)
#define Fordown(i , j , k) for (register int i = (j) , i##_end_ = (k) ; i >= i##_end_ ; -- i)
using namespace std;
typedef long long LL;
template <typename T> inline bool chkmax(T &a , T b) { return a < b ? (a = b , 1) : 0; }
int _ , __; char c_;
inline int read() {
for (_ = 0 , __ = 1 , c_ = getchar() ; !isdigit(c_) ; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; isdigit(c_) ; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48); return _ * __;
}
const int maxn = 100010;
struct Item
{
int x , y , z;
bool operator < (const Item &item) const { return x - y > item.x - item.y; }
}a[maxn];
int X, Y, Z, n, q[maxn], cnt;
LL Ans, Sumy, Sumz, pre[maxn];
inline void Init()
{
X = read(); Y = read(); Z = read(); n = X + Y + Z;
For(i, 1, n) a[i].x = read(), a[i].y = read(), a[i].z = read();
sort(a + 1 , a + 1 + n);
For(i, 1, n) a[i].x -= a[i].z, a[i].y -= a[i].z, Sumz += a[i].z;
}
inline void Solve()
{
For(i, 1, X) q[cnt ++] = -a[i].x, pre[X] += a[i].x;
make_heap(q , q + cnt);
For(i, X + 1, n - Y) q[cnt ++] = -a[i].x, push_heap(q, q + cnt), pre[i] = (pre[i - 1] + a[i].x + q[0]), pop_heap(q, q + (cnt --));
cnt = 0; For(i, n - Y + 1, n) q[cnt ++] = -a[i].y, Sumy += a[i].y;
make_heap(q, q + cnt);
Ans = Sumy + pre[n - Y];
Fordown(i, n - Y, X + 1)
q[cnt ++] = -a[i].y, push_heap(q, q + cnt), Sumy += a[i].y + q[0], chkmax(Ans, Sumy + pre[i - 1]), pop_heap(q, q + (cnt --));
printf("%lld\n" , Ans + Sumz);
}
int main()
{
Init();
Solve();
return 0;
}