CF1474C Array Destruction 题解 贪心
题目链接:http://codeforces.com/contest/1474/problem/C
解题思路:贪心。和 \(x\) 必定是单调递减的(因为所有 \(a_i\) 都大于 \(0\))。所以一开始的 \(x\) 必定是最大的那个数加上另一个数,最大的那个数是可以确定的, 另一个数 不能确定,所以需要枚举。
所有一开始需要枚举 \(2n-1\) 个 另一个数 ,和最大的那个数一起确定初始的 \(x\),然后我们接下来每一步都知道当前的 \(x\),并且组成 \(x\) 的两个数中有一个是当前没有使用过的最大值,另一个数(\(x -\) 最大数)可以二分得到,总的时间复杂度为 \(O((2n-1) \times n \log n) = O(n^2 \log n)\)。
示例代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2020;
int T, n, a[maxn], ans;
multiset<int> st;
vector<pair<int, int> > vec;
bool _check(int ii) {
st.clear();
for (int i = 0; i < 2*n-1; i ++) {
if (i == ii) continue;
st.insert(a[i]);
}
vec.clear();
vec.push_back({a[2*n-1], a[ii]});
ans = a[2*n-1] + a[ii];
int tmp = a[2*n-1];
for (int i = 1; i < n; i ++) {
multiset<int>::iterator it = st.end(), it2;
it --;
int x = *it;
st.erase(it);
it2 = st.lower_bound(tmp - x);
if (it2 == st.end()) return false;
int y = *it2;
if (x + y != tmp) return false;
vec.push_back({x, y});
tmp = max(x, y);
st.erase(it2);
}
return true;
}
bool check() {
for (int i = 0; i < 2*n-1; i ++) if (_check(i)) return true;
return false;
}
int main() {
scanf("%d", &T);
while (T --) {
scanf("%d", &n);
for (int i = 0; i < 2*n; i ++) scanf("%d", a+i);
sort(a, a+2*n);
if (check()) {
puts("YES");
printf("%d\n", ans);
for (auto x : vec) printf("%d %d\n", x.first, x.second);
}
else puts("NO");
}
return 0;
}