【Codeforces Round #695 (Div. 2) C】Three Bags
题目链接
翻译
给你 \(3\) 个多重集,第 \(i\) 个集合有 \(n[i]\) 个数字。
从两个不同集合中分别取出数字 \(x\) 和 \(y\),则从两个集合中分别删去 \(x\) 和 \(y\), 然后在第 \(1\) 个集合中(取出 \(x\)
的那个集合) 加入元素 \(x-y\)。
要求最后只有一个集合中剩下一个数字,问你这个数字最大可以是多少。
题解
思维
把操作 \((x,y)\) 看做是有向树的一条边,边由儿子节点指向父节点,其中儿子节点表示 \(y\),父节点表示 \(x\)。
即操作过后, 儿子节点没了,父节点变成 \(x-y\),直到只剩下一个根节点为止。
那么,形成的这棵树有 \(n_1+n_2+n_3\) 个节点。
模拟一下会发现,最后剩下的一个数字就为树中偶数层的节点之和减去奇数层的节点之和(根视为第 \(0\) 层)。
问题就转化成让奇数层上数字之和最小。
但是奇数层上的数字是有限制的,会发现奇数层上的节点要满足以下两个条件之一:
- 1.奇数层上的节点全都来自同一个集合 \(X\) 中,且这个集合 \(X\) 中的全部元素都在奇数层上。
- 2.奇数层上的节点来自至少两个集合中的数字。
证明如下: 如果奇数层上的节点全都来自同一个集合 \(X\) ,但是没有包括 \(X\) 中的全部元素的话,那么 \(X\)
中剩下的元素怎么办?只能放在偶数层了,但是这就和题目中的操作冲突了,因为这个偶数层的节点会和奇数层
的来自同一集合中的元素进行合并操作了,非法。所以只能全都在同一层。
而如果奇数层上的节点至少来自两个集合则没有这个烦恼了,父节点是相同集合的元素的话,就全都扔在另外一个
集合的节点下面就好了。
这样的话,我们就最多用一个 \(3\) 层的如上所述的树就能完成构造了,奇数层就是第 \(1\) 层,可以是两个集合中各自
最小的元素的加和,或者全都来自同一个集合中的数字的加和。排个序,考虑一下这几种情况就好。
代码
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 3e5;
int n[4];
int a[4][N + 10];
int main() {
#ifdef LOCAL_DEFINE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(0), cin.tie(0);
for (int i = 1; i <= 3; i++) {
cin >> n[i];
}
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= n[i]; j++) {
cin >> a[i][j];
}
sort(a[i] + 1, a[i] + 1 + n[i]);
}
LL ans = 0;
LL temp1 = 0;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= n[i]; j++) {
temp1 += a[i][j];
}
}
//1.奇数层全都来自同一个bag
for (int i = 1; i <= 3; i++) {
LL temp2 = 0;
for (int j = 1;j <= n[i];j++){
temp2 += a[i][j];
}
ans = max(ans, temp1 - 2 * temp2);
}
//1.奇数层来自两个不同的bag
for (int i = 1; i <= 3; i++) {
LL temp2 = 0;
//1,2
temp2 = a[1][1] + a[2][1];
ans = max(ans, temp1 - 2 * temp2);
//1,3
temp2 = a[1][1] + a[3][1];
ans = max(ans, temp1 - 2 * temp2);
//2,3
temp2 = a[2][1] + a[3][1];
ans = max(ans, temp1 - 2 * temp2);
}
cout << ans << endl;
return 0;
}