题目
下面我们考虑几种情况:
-
硬币全为偶数:答案全为0;
-
硬币有一个奇数:设奇数为odd,偶数从大到小为e1,e2,...。那么答案k从1到n分别为odd+e1,odd+e1+e2,...。
-
硬币有多个奇数:设奇数从大到小为o1,o2,...,偶数从大到小为e1,e2,...,em。
那么k从1到m,我们取odd为o1,此时情况等价于情况2;
k=m+1,删去最小偶数em,加入除o1外的两个奇数,此时答案为o1+prefixeven[m-1];
k=m+2,在k=m+1的基础上加入em,此时答案为o1+prefix[m];
k=m+2,删去em,再加入两个o1外两个奇数,此时答案为o1+prefixeven[m-1];
k=m+3,加入em;
以此类推。。。
AC代码如下
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N=2e5+8;
int a[N];
void solve(){
int n;
cin>>n;
vector<int>odd,even;
for(int i=0;i<n;i++){
cin>>a[i];
if(a[i]&1)odd.push_back(a[i]);
else even.push_back(a[i]);
}
sort(odd.begin(),odd.end());
sort(even.begin(),even.end());
reverse(even.begin(),even.end());
vector<int>pe((int)even.size()+1);//预处理偶数前缀和
if((int)even.size()>0){
pe[0]=0;
for(int i=0;i<(int)even.size();i++){
pe[i+1]=pe[i]+even[i];
}
}
int addodd=1,addeven=0;//第一次操作最优是加入偶数
if((int)odd.size()==0)addodd=0,addeven=1;//如果没有奇数第一项只能加偶数
for(int k=1;k<=n;k++){
if(k>1){
if(addeven<(int)even.size())addeven++;//因为无特殊情况,前面的操作只加了一个奇数,所以尽可能先把偶数加完
else {
if(addodd+2<=(int)odd.size()&&addeven){偶数加完后优先考虑加两个奇数,去一个最小偶数
addodd+=2;
addeven--;
}else addodd++;//奇数不够加2,只能加一个奇数
}
}
if(addodd&1){
cout<<odd.back()+pe[addeven]<<" ";//奇数个数为奇数时,答案为最大奇数+偶数前缀和
}
else cout<<"0 ";//奇数个数为偶数时答案必为0
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
完结撒花!!!