题目链接:https://codeforces.com/contest/1467/problem/C
题目大意就为在三个袋子中任选两个袋子,分别从两个袋子中取出一个数a,b,使a = a - b,b被删除。一直重复进行此操作,使三个袋子中最终只剩下一个袋子里有一个值,且这个值是经过此变换得来的最大值,求这个最大值。
思路
(最开始直接看漏了要从两个袋子里面取值,然后就直接将所有输入值sort,wa到怀疑人生。。。)
我们先假设三个袋子为A,B,C。假设三个袋子中各自只有一个值,分别为a,b,c、,首先我们取b,c得到b’ = b - c,然后我们取a,b’得到a’ = a - b’,那我们进行的操作就是res = a - (b - c) = a - b + c;以此类推我们还可以得到res = b - a + c;res = a - c + b。那么我们所求的答案就应该是三个res中最大的那个,换一个角度来说max = a + b + c - 2 * MIN(a, b, c)。
那么当袋子里不止一个数字的时候呢。我们通过刚刚的例子可以看到,一个数要是直接到达终点袋子,若该数经历过奇数次变换位置就是负数(如b直接到达c,b为负数,即c - b);经历偶数次变换位置就为正数(如b先到a再到c,即c - (a - b))。那么我们只需要让尽量小且尽量少的数经历奇数次变换,即直接到目标袋子,而尽量大尽量多的数经历偶数次变换,即先到较小数的袋子,变为(min - max),再到目标袋子。
这就有两种实现方法
方法一:将一个袋子作为较小数袋,成为较大数的过渡袋。比如将A中的值的和很小,那么我们将A变为过渡袋,B、C当中的所有值(此处假设C为目标袋子)都要经过A再到目标位置那么Ai = (Ai - Bj) - Ck ,则resmax = sum(B) + sum(C) - sum(A),(对于目标袋子C来说,C中的值c→a→c,就 好像 没动)。如果sum(A)没有足够的小,那么就会引起下一个方法
方法二:若B1 + A1小于任何一个袋子中所有数的和,那么我们将B1 和 A1看作过渡位置,即将A2 – Alen(A)先经过B1; B2 – Blen(B)先经过A1,再到目标袋子,而C袋子则随意经过其中一个袋子,再到目标袋子即C袋(就相当于没变化);
在选择方法的时候,~~(小孩子才做选择,成年人的我都要,嘿嘿)~~我们只需要先将A,B,C袋子中的数字排序,再分别求和SUMA,SUMB,SUMC,再任意组合其中两个袋子的最小值计算和,然后比较这六个值的最小值得到min,然后再将所有数字加起来的时候,减去2 * min就好了(一定是二倍,其中自己想)
AC代码
#include <bits/stdc++.h>
using namespace std;
const int M = 3e5 + 10;
typedef long long ll;
int a[M], b[M], c[M];
void in(int *a, int n, ll &sum){
for(int i = 0; i < n; i ++) {
cin >> a[i];
sum += a[i];
}
sort(a, a + n);
}
int main (){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int n1, n2, n3; cin >> n1 >> n2 >> n3;
ll s1 = 0, s2 = 0, s3 = 0;
in(a, n1, s1);
in(b, n2, s2);
in(c, n3, s3);
ll sum = s1 + s2 + s3;
ll sub = min(s1, min(s2, s3));
sub = min(sub, 1ll * a[0] + b[0]);
sub = min(sub, 1ll * b[0] + c[0]);
sub = min(sub, 1ll * a[0] + c[0]);
cout << sum - 2 * sub << "\n";
return 0;
}