AGC018C
先设 n=x+y+z。
首先将三元组 (a,b,c) 替换成二元组 (e=b−a,f=c−a)。即先默认所有人拿金币。
然后问题转换为在 n 个二元组中选 y 个获得 e 收益,选 z 个获得 f 收益,最大化总收益。
对于两个二元组 (ei,fi),(ej,fj),假设 i 选 f,j 选 e。考虑什么时候交换他们的选择收益不会变少。即 ei+fj≥ej+fi,移项得 ei−fi≥ej−fj,那么通过排序使得二元组按 e−f 单调不降。就有对于任意 i<j,如果 i 选 f,j 选 e,那么交换两者状态一定不会变差。
换言之,存在最优解满足选 e 的全在选 f 的左边。也就是说存在一个 k,使得 1∼k 中选 y 个 e,k+1∼n 中选 z 个 f。
这个就可以通过优先队列处理出每个前缀前 y 大的 e 的和以及每个后缀前 z 大的 f 的和。
最后枚举 k 即可得出答案。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
int x, y, z, n;
struct node {
int b, c;
} p[N];
ll sum, mx = -1e18;
ll L[N], R[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, a, b, c; i <= n; ++i) {
scanf("%d%d%d", &a, &b, &c);
sum += a, p[i].b = b - a, p[i].c = c - a;
}
sort(p + 1, p + n + 1, [](node x, node y) {
return x.b - x.c > y.b - y.c;
});
for (int i = 1; i <= n; ++i) {
L[i] = L[i - 1] + p[i].b;
q.push(p[i].b);
if (q.size() > y) {
L[i] -= q.top();
q.pop();
}
}
while (!q.empty()) q.pop();
for (int i = n; i; --i) {
R[i] = R[i + 1] + p[i].c;
q.push(p[i].c);
if (q.size() > z) {
R[i] -= q.top();
q.pop();
}
}
for (int i = y; i <= n - z; ++i) mx = max(mx, L[i] + R[i + 1]);
printf("%lld", sum + mx);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】