codeforces 2018.9.21 div2 C
这次的bug原因是英语不好,题目理解错了。
题目要求,能否将给出的多元集合划分成两个集合,使得每个集合中,只出现了一次的元素的个数相等。我理解成了,只对于在原集合中出现了一次的元素才计数。
例如,下面这个样例: 6 1 3 5 6 6 6
如果按照我的理解,只出现一次的数字只有1、3、5,则无论如何不能平均分到两个集合里;但是答案是可以的,例如可以分成1 3 6 6、5 6,这两个集合,每个里面只出现一次的数字个数相等。
乍一看没法做,但是考虑题中的情况:如果数字仅仅出现了一次,则必须被分配过程考虑在内;如果出现了两次,则怎么分都可以——两个分开,一边一个,都加一,无数量影响,若两个一起放,则放在哪一边都不需要计数,也无影响;如果出现了三次及以上,则它既可以看成无影响,也可以单独拆出一个,补到数目不足的那个集合去,而自己原先的这个集合仍然无影响。
那么只需要考虑这几种情况(出现次数都是相对于原组合而言):1.出现一次的元素个数为奇,且三次及以上元素无,则一定不能被等分,否;2.一次的元素个数为偶,则无论三次及以上元素的有无,都一定能被等分。3.一次的元素个数为奇(设为m),且三次及以上元素有。则只需要把出现一次的元素组成的数组的前m/2-1个元素的对应位置处的字符换一下,再把出现三次及以上的元素组成的数组的第一个元素对应位置处的字符也换一下,就行了。(如原先是B,换成A,当然这需要提前存一下位置,考虑到最多只涉及到一个字符的特殊替换,所以位置只保存其中一个就行了)。
下面是代码
#include <bits/stdc++.h>
#define N 105
using namespace std;
int s[N],des[N];
char ans[N];
map<int,int> mp;
vector<int> three,one;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
fill(ans,ans+N,'B');
int n;
cin>>n;
for (int i=0;i<n;i++) {
cin>>s[i];
mp[s[i]]++;
des[s[i]]=i;
}
map<int,int>::iterator it1=mp.begin();
for (;it1!=mp.end();it1++) {
if ((*it1).second==1)
one.push_back((*it1).first);
else if ((*it1).second>=3)
three.push_back((*it1).first);
}
if (((int)one.size()&1)&&three.empty())
cout<<"NO"<<endl;
else {
cout<<"YES"<<endl;
if (!((int)one.size()&1)) {
for (int i=0;i<(int)one.size()/2;i++) ans[des[one[i]]]='A';
for (int i=0;i<n;i++) cout<<ans[i];
cout<<endl;
}
else if (((int)one.size()&1)&&!three.empty()) {
for (int i=0;i<(int)one.size()/2;i++) ans[des[one[i]]]='A';
ans[des[three[0]]]='A';
for (int i=0;i<n;i++) cout<<ans[i];
cout<<endl;
}
}
return 0;
}
有点意外的是丧心病狂的113个用例,有点吓人。