CF1474C. 数组摧毁
CF1474C. 数组摧毁
题目描述
有一个数组 \(a\) 包含 \(2n\) 个正整数。我们需要按照下列规则删除数组中所有数。
1、一开始,选择任何一个正整数 \(x\)。
2、之后,你需要做下面的操作 \(n\) 次。
- 选择两个元素,它们的和等于 \(x\)。
- 从数组 \(a\) 中移除这两个元素,替换 \(x\) 为两个数字中的较大值。
输出你的方案。
输入
第一行包含一个整数 \(t\)。
之后第一行包含一个整数 \(n\)。
输出
如果存在方案,输出 "YES",并且输出方案,否则输出 "NO"。
数据范围
\(1\le t\le 1000\)
\(1\le n\le 1000\)
\(1\le a_i\le 10^6\)
\(\sum n\le 1000\)
样例输入
4
2
3 5 1 2
3
1 1 8 8 64 64
2
1 1 2 4
5
1 2 3 4 5 6 7 14 3 11
样例输出
YES
6
1 5
2 3
NO
NO
YES
21
14 7
3 11
5 6
2 4
3 1
思路
\(x\) 每次操作后值都会减小。
假设我们数列中存在整数 \(a_i\le a_j\le a_k\)。如果我们删除 \(a_i+a_j=x\),那么我们之后就不能删除 \(a_k\) 了。所有我们每次操作应该删除最大的元素。
如果我们知道 \(x\) 是最大的元素,我们很容易能知道第二个我们删除的元素。
我们可以尝试第一次操作的所有可能组合,之后就能固定下来了。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=200010;
int main(){
int t; cin>>t; while(t--){
int n; cin>>n;
multiset<int> st;
multiset<int> st2;
vector<int> a(2*n);
for(int i=0;i<2*n;i++){
cin>>a[i];
st.insert(a[i]);
}
//st2=st;
sort(a.rbegin(),a.rend());
int x=a[0];
auto it=st.find(x);
st.erase(it);
bool flag=false;
vector<int> ve;
int t=0;
t+=x;
for(int i=1;i<2*n;i++){
t+=a[i];
st2=st;
auto it=st2.find(a[i]);
st2.erase(it);
ve.clear();
ve.push_back(x); ve.push_back(a[i]);
int pre=x;
while(st2.size()){
int maxx=*(--st2.end());
int minn=pre-maxx;
auto it=st2.find(maxx); st2.erase(it);
if(st2.find(minn)==st2.end()) break;
it=st2.find(minn); st2.erase(it);
pre=maxx;
ve.push_back(maxx); ve.push_back(minn);
}
if(st2.size()==0) {flag=true; break;}
t-=a[i];
}
if(flag){
puts("YES");
cout<<t<<endl;
for(int i=0;i<ve.size();i++) {
cout<<ve[i];
if(i%2==0) cout<<" ";else cout<<"\n";
}
//cout<<endl;
}else{
puts("NO");
}
}
return 0;
}