题意: 问是否能选定一个初始值x,使得能按一定要求消除掉大小为 n*2 的数组所有值。要求:第一次删除两个数的和为x,以后每次删除的两数之和都为上次删除数的max。问是否能正好删除数组的所有值,并输出构造的删除顺序。
思路:
- 由于本题数据范围不大,可以考虑暴力的思维。
- 每次删除的数必定是当前数组的最大值和另一个特定的数(两数之和必定等于上一轮删除的最大数),所以只要 x 确定后,之后的删除顺序便都确定了。
- 而 x 就由第一次删除的两个数来决定,其中一个为整个数组的max,另一个便可以暴力枚举了。
- 至于为什么每次都得删除当前数组最大值,这个就不言而喻了嘛。如果每次不删除最大值,之后就不可能再消除它了,毕竟下一次删除的和才到上一次的max。
- 具体细节见代码注释。
代码实现:
#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ll long long
#define int long long
#define pii pair<int, int>
#define lowbit(x) (x &(-x))
#define ls(x) x<<1
#define rs(x) (x<<1+1)
#define me(ar) memset(ar, 0, sizeof ar)
#define mem(ar,num) memset(ar, num, sizeof ar)
#define rp(i, n) for(int i = 0, i < n; i ++)
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define pre(i, n, a) for(int i = n; i >= a; i --)
#define IOS ios::sync_with_stdio(0); cin.tie(0);cout.tie(0);
const int way[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
using namespace std;
const int inf = 0x7fffffff;
const double PI = acos(-1.0);
const double eps = 1e-6;
const ll mod = 1e9 + 7;
const int N = 2e5 + 5;
int t, n, m, a[N];
map<int, int> ct, mp;
vector<int> b;
signed main()
{
IOS;
cin >> t;
while(t --){
cin >> m;
n = m*2;
ct.clear(); mp.clear(); b.clear();//更新所有中间数组
for(int i = 1; i <= n; i ++){
cin >> a[i];
mp[a[i]] ++;
}
ct = mp;
sort(a+1, a+n+1);
// for(int i = 1; i <= n; i ++){
// cout << "debug: " << a[i] << " " << ct[a[i]] << endl;
// }
int flag = 0, tmp = a[n], res;
for(int i = 1; i < n; i ++){
res = a[i]; ct[res] --; //枚举选定与首个max一起消除的另一个数
b.push_back(res);
b.push_back(a[n]);
ct[a[n]] --;
for(int j = n-1; ~j; j --){
if(!j) {flag = 1; break;} //表示所有数都已消除
if(!ct[a[j]]) continue; //如果当前这个max已经不存在
// cout << "tmp: " << tmp << endl;
// cout << "debug: " << a[j] << " " << ct[a[j]] << " " << tmp-a[j] << " " << ct[tmp-a[j]] << endl;
if(!ct[tmp-a[j]]||(ct[a[j]]==1&&tmp==a[j]*2)){ //如果无法找到与当前max匹配的数,特别注意tmp==a[j]*2的情况
b.clear();
ct = mp;
tmp = a[n]; //恢复所有初始值
break;
}
else{
b.push_back(tmp-a[j]);
b.push_back(a[j]); //先将两个数加入答案集合并从原先数集中消除
ct[a[j]] --; ct[tmp-a[j]] --;
tmp = a[j]; //更新当前max
}
}
if(flag) break;
}
cout << (flag ? "YES":"NO") << endl;
if(flag){
cout << a[n]+res << endl;
for(int i = 0; i < n; i += 2)
cout << b[i] << " " << b[i+1] << endl;
}
}
return 0;
}
后期看见一篇利用multiset的题解还比较好。