首页 > 其他分享 >AGC018C

AGC018C

时间:2022-10-25 15:59:34浏览次数:55  
标签:二元 int ll d% 中选 pop AGC018C

先设 \(n=x+y+z\)。

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

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

对于两个二元组 \((e_i,f_i),(e_j,f_j)\),假设 \(i\) 选 \(f\),\(j\) 选 \(e\)。考虑什么时候交换他们的选择收益不会变少。即 \(e_i+f_j\ge e_j+f_i\),移项得 \(e_i-f_i\ge e_j-f_j\),那么通过排序使得二元组按 \(e-f\) 单调不降。就有对于任意 \(i\lt j\),如果 \(i\) 选 \(f\),\(j\) 选 \(e\),那么交换两者状态一定不会变差。

换言之,存在最优解满足选 \(e\) 的全在选 \(f\) 的左边。也就是说存在一个 \(k\),使得 \(1\sim k\) 中选 \(y\) 个 \(e\),\(k+1\sim 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;
}

标签:二元,int,ll,d%,中选,pop,AGC018C
From: https://www.cnblogs.com/Kobe303/p/16825083.html

相关文章