[AGC018C] Coins
妙妙题。
首先假设全部选铜币,先让答案加上 \(\sum\limits_{i=1}^{x+y+z}C_i\),然后令原先的 \(A_i = A_i - C_i,B_i = B_i - C_i\),问题就变成了:
从 \(n = x + y + z\) 中选出 \(x\) 个 \(A\) 和 \(y\) 个 \(B\) 使得总和最大。
对于 \(i,j\),若 \(A_i + B_j > A_j + B_i\),那么假如选择 \(A_j\) 和 \(B_i\),交换两者会更优
移项可得 \(A_i - B_i > A_j - B_j\),按 \(A_i - B_i\) 从大到小排序就可以得到一个很重要的性质:
选出来的 \(x\) 个 \(A\) 一定在 \(y\) 个 \(B\) 的前面。
那么问题就好办了,预处理出在前 \(i\) 个人中选出 \(x\) 个 \(A\) 的最大值和后 \(i\) 个人中选出 \(y\) 个 \(B\) 的最大值,枚举分界点取 \(\max\) 即可,时间复杂度 \(\mathrm{O(n \log n)}\)。
\(\texttt{Code:}\)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
struct st {int a, b;} p[N];
bool cmp(st a, st b) {return a.a - a.b > b.a - b.b;}
int x, y, z, n;
ll ans, pre[N], suc[N];
priority_queue<int, vector<int>, greater<int> > q;
int main() {
scanf("%d%d%d", &x, &y, &z);
n = x + y + z;
for (int i = 1; i <= n; i++) {
int c; scanf("%d%d%d", &p[i].a, &p[i].b, &c);
ans += c; p[i].a -= c; p[i].b -= c;
}
sort(p + 1, p + n + 1, cmp);
for (int i = 1; i <= x; i++) q.push(p[i].a), pre[x] += p[i].a;
for (int i = x + 1; i <= n - y; i++) {
pre[i] = pre[i - 1];
if (q.top() < p[i].a) {
pre[i] += p[i].a - q.top(); q.pop();
q.push(p[i].a);
}
}
while (!q.empty()) q.pop();
for (int i = n; i >= n - y + 1; i--) q.push(p[i].b), suc[n - y + 1] += p[i].b;
for (int i = n - y; i > x; i--) {
suc[i] = suc[i + 1];
if (q.top() < p[i].b) {
suc[i] += p[i].b - q.top(); q.pop();
q.push(p[i].b);
}
}
ll dt = -1e18;
for (int i = x; i <= n - y; i++) dt = max(dt, pre[i] + suc[i + 1]);
printf("%lld", ans + dt);
return 0;
}

浙公网安备 33010602011771号