欢迎来到下蛋爷之家|

下蛋爷

园龄:4年2个月粉丝:8关注:23

[AGC018C] Coins 题解

Description

x+y+z 个人,第 i 个人有 Ai 个金币,Bi 个银币,Ci 个铜币。

要选出 x 个人获得其金币,选出 y 个人获得其银币,选出 z 个人获得其铜币。在不重复选某个人的情况下,最大化获得的币的总数。

x+y+z105

Solution

先默认每个人都选 C,让每个 Ai,Bi 都减 Ci,相当于就是要选出 x 个人选 Ay 个人选 B,最大化总和。

注意到如果 iAjBAi+Bj<Aj+Bi 则把 i,j 互换会更优,这个条件等价于 AiBi<AjBj

所以如果把所有人按照 AiBi 排序,选 B 的一定是选了的人里最靠前的 y 个,而选 A 的一定是最靠后的 x 个,搞个优先队列即可。

时间复杂度:O(nlogn)

Code

#include <bits/stdc++.h>
#define int int64_t
const int kMaxN = 1e5 + 5;
int n, x, y, z, ans;
int a[kMaxN], b[kMaxN], c[kMaxN], pre[kMaxN], suf[kMaxN];
std::vector<std::tuple<int, int, int>> vec;
void getpre() {
std::multiset<int> st;
int sum = 0;
for (int i = 1; i <= n; ++i) {
int val = std::get<2>(vec[i]);
if (st.size() < y) sum += val, st.emplace(val);
else if (*st.begin() < val) sum += val - *st.begin(), st.erase(st.begin()), st.emplace(val);
if (i >= y) pre[i] = sum;
}
}
void getsuf() {
std::multiset<int> st;
int sum = 0;
for (int i = n; i; --i) {
int val = std::get<1>(vec[i]);
if (st.size() < x) sum += val, st.emplace(val);
else if (*st.begin() < val) sum += val - *st.begin(), st.erase(st.begin()), st.emplace(val);
if (i <= n - x + 1) suf[i] = sum;
}
}
void dickdreamer() {
std::cin >> x >> y >> z;
n = x + y + z;
for (int i = 1; i <= n; ++i) {
std::cin >> a[i] >> b[i] >> c[i];
ans += c[i], a[i] -= c[i], b[i] -= c[i];
vec.emplace_back(a[i] - b[i], a[i], b[i]);
}
vec.emplace_back(-2e9, 0, 0);
std::sort(vec.begin(), vec.end());
getpre(), getsuf();
int tmp = -1e18;
for (int i = y; i <= n - x; ++i)
tmp = std::max(tmp, pre[i] + suf[i + 1]);
std::cout << ans + tmp << '\n';
}
int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}
posted @   下蛋爷  阅读(37)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起