[AGC018C] Coins 题解

Description

x+y+zx+y+z 个人,第 ii 个人有 AiA_i 个金币,BiB_i 个银币,CiC_i 个铜币。

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

x+y+z105x+y+z\le 10 ^ 5

Solution

先默认每个人都选 CC,让每个 Ai,BiA_i,B_i 都减 CiC_i,相当于就是要选出 xx 个人选 AAyy 个人选 BB,最大化总和。

注意到如果 iiAAjjBBAi+Bj<Aj+BiA_i+B_j<A_j+B_i 则把 i,ji,j 互换会更优,这个条件等价于 AiBi<AjBjA_i-B_i<A_j-B_j

所以如果把所有人按照 AiBiA_i-B_i 排序,选 BB 的一定是选了的人里最靠前的 yy 个,而选 AA 的一定是最靠后的 xx 个,搞个优先队列即可。

时间复杂度:O(nlogn)O(n\log n)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#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;
}

[AGC018C] Coins 题解
https://sobaliuziao.github.io/2024/02/27/post/37118534.html
作者
Egg_laying_master
发布于
2024年2月27日
许可协议