C. Array Destruction
题意:给出一个数列,有 2 n 2n 2n个数,问是否存在一个 x x x,使 a i + a j = x ( i ! = j ) a_i+a_j=x(i!=j) ai+aj=x(i!=j)。我们再将 x = m a x ( a i , a j ) x=max(a_i,a_j) x=max(ai,aj),之后重复前一个操作,每个数只能用一次,问是否存在一个数 x x x,使全部的数都被选到,如果存在输出选择顺序。
思路:最大值肯定是第一个被选的值之一,(简单证明:如果第一次选的是第二大的值,那最大的值就一定选不上了。)然后,我们再枚举另一个数 a j a_j aj找到 x x x,在第二次选择时,已知 x = x= x=最大值,第二大的值,这样我们直接去剩下的数里面去找另一个值,如果存在,继续直到能够选完全部的数,如果不存在,换一个数 a j a_j aj重新开始判断,直到全部的数都被枚举完之后。
选择的过程中用到了 m u l t i s e t multiset multiset,方便选择。
C o d e Code Code
#include<bits/stdc++.h>
using namespace std;
vector<int> a;
//对于每种 第一次选择判断是否是可以成功的。
vector<int> check(vector<int> xt, int u, int n) {
multiset<int> s;
vector<int> ans;
for(auto it:x) s.insert(it);
for(int i=0; i<n; i++) {//n次选择。
auto it1 = s.end();
it1--;//当前最大值。
int y = u-*it1;//另一个数。
s.erase(it1);
auto it2 = s.find(y);
if(it2 == s.end()) return {};//选择失败,返回空数组。
//把选择顺序加入数组中。
ans.push_back(y);
ans.push_back(u-y);
u = max(y, u-y);
s.erase(it2);
}
return ans;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int t;
cin >> t;
while(t--) {
int n, x, flag = 0;
cin >> n;
for(int i=0; i<2*n; i++) {
cin >> x;
a.push_back(x);
}
sort(a.begin(), a.end());
for(int i=0; i<2*n-1; i++) {//枚举每个a_j
int k = a[i] + a[a.size()-1];
vector<int> v = check(a, k, n);
//选择成功
if(v.size()) {
printf("Yes\n%d\n", k);
for(int j=0; j<n; j++) {
printf("%d %d\n", v[j*2], v[j*2+1]);
}
flag = 1;
break;
}
}
if(!flag) printf("No\n");
a.clear();
}
return 0;
}