[AGC018C] Coins

\(\texttt{link}\)

妙妙题。

首先假设全部选铜币,先让答案加上 \(\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;
}
posted @ 2021-11-18 21:34  klii  阅读(64)  评论(0)    收藏  举报