AGC018C

先设 n=x+y+z

首先将三元组 (a,b,c) 替换成二元组 (e=ba,f=ca)。即先默认所有人拿金币。

然后问题转换为在 n 个二元组中选 y 个获得 e 收益,选 z 个获得 f 收益,最大化总收益。

对于两个二元组 (ei,fi),(ej,fj),假设 ifje。考虑什么时候交换他们的选择收益不会变少。即 ei+fjej+fi,移项得 eifiejfj,那么通过排序使得二元组按 ef 单调不降。就有对于任意 i<j,如果 ifje,那么交换两者状态一定不会变差。

换言之,存在最优解满足选 e 的全在选 f 的左边。也就是说存在一个 k,使得 1k 中选 yek+1n 中选 zf

这个就可以通过优先队列处理出每个前缀前 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;
}
posted @   Kobe303  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示