https://codeforces.com/contest/1467/problem/C
题意
有三个袋子,里面分别装有
n
1
,
n
2
,
n
3
n_1,n_2,n_3
n1,n2,n3 个数字。可以对这些数字进行如下操作:从任意两个袋子里各选一个数字,分别为
a
,
b
a,b
a,b,将
a
a
a 改为
a
−
b
a-b
a−b,将
b
b
b 删去。
在若干次操作后,只剩一个数字,求这个数的最大值
分析
假设三个袋子分别为 A , B , C A,B,C A,B,C 。题目给出的操作可以看作是将 b b b 乘 − 1 -1 −1 后,移到装有 a a a 的袋子里。我们的目标就是把所有数移到同一个袋子里。假设要把所有数都移到 A A A 中,那么
考虑移动一个数
例如,将 x x x 从 B B B 移到 A A A,有两种方法
- 直接把 x x x 移到 A A A , x x x 变成 − x -x −x
- 把 x x x 先移到 C C C 中,变为 − x -x −x;再从 C C C 移到 A A A 中,变回 x x x
按照题目给出的操作,移动时还需在要移入的袋子里找另一个数,仍以将 x x x 从 B B B 移到 A A A 为例,前文给出的两种方法需要改成
- 直接把 x x x 移到 A A A:在 A A A 中找一个数 y y y 变成 y − x y-x y−x , B B B 里的 x x x 删去
- 把 x x x 先移到 C C C 中,再从 C C C 移到 A A A:在 C C C 中找一个数 y y y 变成 y − x y-x y−x, B B B 中的 x x x 删去;在 A A A 中找一个数 z z z 变成 z + x − y z+x-y z+x−y ( z − ( y − x ) z-(y-x) z−(y−x)), C C C 中的 y − x y-x y−x 删去
不难发现,使用第二种方法,可以看作将 x x x 直接移入 A A A,但是 y y y 会被减去。
移动所有数
用上述方法,要将所有数依次移入 A A A 中,需要在 B B B 和/或 C C C 中选取一个或一些数用于中转,这些用于中转的数最后被减去,其他数则是直接被 “移入” A A A。可以分以下两种情况讨论
- 在 B B B 和 C C C 中分别选取一个/一些数用于中转。由于用于中转的数最后会被减去,因此应该分别选两个袋子里最小的一个。
- 在 B B B 或 C C C 中选取一个/一些作为中转。假设选取 B B B 中的数用于中转,则要将 C C C 中的数全部移入 B B B ,再将 B B B 中的数移入 A A A。那么,原来属于 C C C 的数被 “移入” A A A;由于 C C C 中没有用于中转的数,原来属于 B B B 的数全部变负,也就是必须选取整个袋子的所有数。
两种方法最后的答案都是 中转数的和 - 非中转数的和,但中转数的选取不同,答案也不同。分别计算这两种方法得到的答案,取较大的即可。
代码
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
ll a[maxn], b[maxn], c[maxn];
int main()
{
int n1, n2, n3;
scanf("%d%d%d", &n1, &n2, &n3);
ll sum[3] = {};
ll ma, mb, mc;
ma = mb = mc = 1e9;
for(int i = 0; i < n1; i ++)
{
scanf("%d", &a[i]);
ma = min(ma, a[i]);
sum[0] += a[i];
}
for(int i = 0; i < n2; i ++)
{
scanf("%d", &b[i]);
mb = min(mb, b[i]);
sum[1] += b[i];
}
for(int i = 0; i < n3; i ++)
{
scanf("%d", &c[i]);
mc = min(mc, c[i]);
sum[2] += c[i];
}
ll tmp1 = min(ma + mb, min(mb + mc, mc + ma));
ll tmp2 = min(sum[0], min(sum[1], sum[2]));
ll ans = sum[0] + sum[1] + sum[2] - 2 * min(tmp1, tmp2);
printf("%lld\n", ans);
return 0;
}