2026ICPC深圳邀请赛 D. City Management

对每次加入工人进行分段处理,同时维护工厂的前 k 大和。
每次处理当前工人,记当前工人和下一工人之间的工厂为新段,计算新段中每个工厂的贡献,然后将其降序排序,最后枚举分配去新工厂的人数和去旧工厂的人数,统计共同的贡献,取最大值就做完了。
这里维护前 k 大值的和用到了对顶堆,详细见代码。

#include <bits/stdc++.h>

// Eternal vigilance.
// from: cpp.json
#define INF 8e18
#define LD long double
#define i128 __int128_t
#define int long long
using namespace std;

void solve() {
    int n;
    cin >> n;

    priority_queue<int, vector<int>, greater<int>> minpq;
    priority_queue<int> maxpq;
    // count: 旧工厂数量
    int sum = 0, count = 0;

    auto adjust = [&](int k) -> void {
        while (minpq.size() < k && !maxpq.empty()) {
            int val = maxpq.top();
            maxpq.pop();
            minpq.push(val);
            sum += val;
        }
        while (minpq.size() > k) {
            int val = minpq.top();
            minpq.pop();
            maxpq.push(val);
            sum -= val;
        }
    };

    auto getSumK = [&](int k) -> int {
        adjust(k);
        return sum;
    };

    auto insert = [&](int x) -> void {
        count++;
        if (!minpq.empty() && x > minpq.top()) {
            minpq.push(x);
            sum += x;
        } else {
            maxpq.push(x);
        }
    };

    vector<pair<char, int>> ops(n + 1);
    vector<int> days;
    for (int i = 1; i <= n; i++) {
        char op;
        cin >> op;
        ops[i].first = op;
        if (op == 'F') {
            cin >> ops[i].second;
        } else {
            days.push_back(i);
        }
    }
    days.push_back(n + 1);

    // K: 当前员工
    int ans = 0, K = 0, lst = 1;
    for (int d : days) {
        if (lst < d) {
            int L = lst;
            int R = d - 1;
            int len = R - L + 1;
            vector<int> ws;
            for (int j = L; j <= R; j++) {
                ws.push_back(ops[j].second * (R - j + 1));
            }
            sort(ws.rbegin(), ws.rend());
            int maxp = 0;
            int cur = 0;
            int limit = min((int) ws.size(), K);
            // j 个人去新工厂, min(K - j, count) 个人去旧工厂
            for (int j = 0; j <= limit; j++) {
                if (j > 0) {
                    cur += ws[j - 1];
                }
                int old = min(K - j, count);
                int os = getSumK(old);
                // 旧工厂 + 新工厂
                maxp = max(maxp, cur + os * len);
            }
            ans += maxp;
            // 插入旧工厂
            for (int j = L; j <= R; j++) {
                insert(ops[j].second);
            }
        }
        if (d <= n) {
            K++;
            lst = d;
        }
    }
    cout << ans << "\n";
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin >> t;

    while (t--) {
        solve();
    }

    return 0;
}
posted @ 2026-04-13 11:09  カガリ  阅读(37)  评论(0)    收藏  举报