CF2127C Trip Shopping
这是回来后的第一篇博客。我也是回来了!
看似是博弈论,实际是脑筋急转弯。我们知道,因为 Bahamin 可以选择不交换,所以交换后的结果一定不能减小,只能增加,因此 Ali 需要尽量不让 Bahamin 去交换数字,所以,即使需要交换 \(k\) 次,但对于 Ali 来说,这 \(k\) 次实际上都是同一个位置(即只让 Bahamin 去交换这一个位置)。即这题实际上只交换一次。
那么目前的问题就转化为了,如何求出这最优的一次交换。为了方便,我们先把 \(a,b\) 中对应项中较大的放到 \(a\) 的位置,小的放到 \(b\) 的位置,然后把 中对应项看成一组,然后按照 \(a\) 从大到小排序。我们设 \(i > j\),且第 i 项的两个数为 \(a,b\),第 \(j\) 项的两个数为 \(x,y\),那么我们可知:\(a>b,x>y,a>x\),那么对于 \(b,x\) 之间的关系有三种:
- \(b>x\),此时交换的结果为 \(a + b - x - y\)
- \(x>b\),此时交换的结果为 \(a + x - b - y\)
- \(x=b\),此时交换的结果为 \(a - y = a + b - x - y = a + x - b - y\),实际上面两个算式子是一样的
而对于这两个项的原本答案为 \(a - b + x - y = a + x - b - y\)。
因此我们可以先把原答案(即交换前)处理出来,然后对于当前的 \(i\) 判断是否存在 \(b > x\) 即可,如果不存在,那么答案就是原答案;如果存在 \(b > x\),那么答案就是 \(原答案 - (a + x - b - y) + a + b - x - y\),即:\(原答案 + 2(b - x)\)。而我们已经把序列按照 \(a\) 的大小排完序了,因此这个 \(x\) 就是我们的 \(a_{i + 1}\)。到这,这题就结束了。
时间复杂度瓶颈在于排序,因此时间复杂度为 \(\operatorname O(n\log n)\)。
可以看出,排序对于这些抽象的问题,具有约束的作用。
代码为:
#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 200010;
int n, m;
PII g[N]; // 为了方便排序,直接使用pair
int main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) scanf("%d", &g[i].x);
for (int i = 1; i <= n; i ++ ) scanf("%d", &g[i].y);
LL ans = 0;
for (int i = 1; i <= n; i ++ )
{
if (g[i].x < g[i].y) swap(g[i].x, g[i].y);
ans += g[i].x - g[i].y;
}
// cout << ans << endl;
sort(g + 1, g + 1 + n);
reverse(g + 1, g + 1 + n);
LL minv = 1e18;
for (int i = 1; i < n; i ++ )
{
minv = min(minv, 2ll * (g[i].y - g[i + 1].x));
}
if (minv > 0) cout << ans + minv << endl;
else cout << ans << endl;
}
return 0;
}