2025/12/11 cf2176problem C题解

26 阅读2分钟

题目

Problem - C - Codeforces

下面我们考虑几种情况:

  1. 硬币全为偶数:答案全为0;

  2. 硬币有一个奇数:设奇数为odd,偶数从大到小为e1,e2,...。那么答案k从1到n分别为odd+e1,odd+e1+e2,...。

  3. 硬币有多个奇数:设奇数从大到小为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;
}

完结撒花!!!