题目链接
翻译
让你一开始的时候选定一个 \(x\) 的值,然后从数组中找到两个数 \(a[i]\) 和 \(a[j]\),使得他们的和为 \(x\),然后从数组中移除掉这两个数字 \(a[i]\) 和 \(a[j]\)。
然后用 \(a[i]\) 和 \(a[j]\) 中的较大者代替 \(x\),重复上述移除过程,直到数组为空。
回答能否找到这样的 \(x\)。如果能找到,输出每次选择的两个数字。
题解
最后每个数字都是要被删掉的。
考虑从小到大排序数组 \(a\), 然后就会发现,我们必须让第 \(2\) 个 \(x\) 是 \(a[n]\),第 \(3\) 个 \(x\) 是 \(a[n-1]\)...
否则,如果第 \(2\) 个 \(x\) 不是 \(a[n]\), 辟如说是 \(a[n-1]\),那么我们就再也没有机会移除掉 \(a[n]\) 了,因为 \(a[n]\) 是最大的,所以
之后都再也不会出现要用 \(a[n]\) 和某个数组成 \(x\) 的情况了, 之后的 \(x\) 都会比 \(a[n]\) 小。
那么就可以知道,第一次选择的 \(x\) 一定是 \(a[n]+a[j]\) 的形式,其中 \(j<n\)。
并且之后, 每次的 \(x\) 的组成都是按顺序由 \(a[n-1],a[n-2]...\) 作为其中一个加起来的。
考虑到这些之后,我们只需要枚举第一个 \(x\) 是由 \(a[i]+a[n]\) 组成,然后 \(x=a[n]\), 继续 \(check\) 一下 \(x-a[n-1]\)是否存在(\(map\)),以此类推来判断删除是否能完成。
代码
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 1000;
int T, n;
int a[2 * N + 10];
map<int, int> dic;
int ope[N + 10][2];
int main() {
#ifdef LOCAL_DEFINE
freopen("in.txt", "r", stdin);
#endif // LOCAL_DEFINE
ios::sync_with_stdio(0), cin.tie(0);
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= 2 * n; i++) {
cin >> a[i];
}
n *= 2;
sort(a + 1, a + 1 + n);
bool finalOK = false;
for (int i = 1; i < n; i++) {
//a[i]+a[n]
int x = a[i] + a[n];
dic.clear();
for (int j = 1; j <= n; j++) {
dic[a[j]]++;
}
bool thisOK = true;
int idx = 0;
for (int j = n; j >= 1; j--) {
if (dic[a[j]] == 0) {
continue;
}
dic[a[j]]--;
int y = x - a[j];
if (dic[y] == 0) {
thisOK = false;
break;
}
dic[y]--;
idx++;
ope[idx][0] = a[j], ope[idx][1] = y;
x = a[j];
}
if (thisOK) {
cout << "YES" << endl;
cout << a[i] + a[n] << endl;
finalOK = true;
break;
}
}
if (!finalOK) {
cout << "NO" << endl;
}
else {
for (int i = 1; i <= n / 2; i++) {
cout << ope[i][0] << " " << ope[i][1] << endl;
}
}
}
return 0;
}