整数分组
给定一个包含 $n$ 个整数 $s_1,s_2, /dots ,s_n$ 的集合 $S$。
我们规定,如果某个整数在一个集合中恰好出现一次,则称该整数为超级数。
例如,集合 $/{1,1,2,3,3,3,4/}$ 中包含两个超级数 $2,4$。
现在,请你将 $S$ 分成两个集合 $A$ 和 $B$(其中一个可以为空),使得集合 $A$ 中超级数的数量与集合 $B$ 中超级数的数量相同(也就是说,集合 $A$ 中恰好出现一次的整数的数量与集合 $B$ 中恰好出现一次的整数的数量相同)。
输入格式
第一行包含一个整数 $n$。
第二行包含 $n$ 个整数 $s_1,s_2, /dots ,s_n$。
输出格式
如果不存在合理的划分方案,则输出一行 $NO$。
否则,第一行输出 $YES$,第二行输出一个长度为 $n$ 的由 $A$ 和 $B$ 构成的字符串,其中的第 $i$ 个字符,如果为 $A$ 则表示 $s_i$ 划分到集合 $A$,如果为 $B$ 则表示 $s_i$ 划分到集合 $B$。
如果方案不唯一,输出任意合理方案均可。
数据范围
前 $6$ 个测试点满足 $2 /leq n /leq 12$。
所有测试点满足 $2 /leq n /leq 100$,$1 /leq s_i /leq 100$。
输入样例1:
4 3 5 7 1
输出样例1:
YES BABA
输入样例2:
3 3 5 1
输出样例2:
NO
解题思路
这题还是比较容易想到的,不过比赛的时候比较紧张,代码写得又长又臭。这一题的细节还是比较多的。
先扫描一遍序列,统计只出现过一次的数的个数,假设是$k$,分情况讨论:
- $2 /mid k$,那么两个集合每个都分$/frac{k}{2}$个就可以了,剩余数的出现次数都大于$1$,可以将他们全部放到$A$或$B$中。最后就可以实现两个集合的超级数的数量都是$/frac{k}{2}$。
- $2 /nmid k$,那么一个集合分$/left/lfloor /frac{k}{2} /right/rfloor$个,另外一个集合分$/left/lfloor /frac{k}{2} /right/rfloor + 1$个。然后看一下剩余的数,如果某个数$x$出现了$2$次,那么无论怎么放$x$,都不能使得某个集合的超级数个数增加$1$个(全部$x$放到某个集合或两个集合各放一个$x$),因此如果某个数出现了$2$次那么这个数没有意义。如果某个数$x$出现超过$2$次,那么把一个$x$放到某个集合中,剩余的$x$都放到另外一个集合中,那么就可以使得只放一个$x$的那个集合的超级数个数加$1$。因此如果$k$是奇数,分完了超级数后某个集合的超级数个数少了一个,此时如果存在某个数的出现次数大于$2$,那么都可以构造一个合法方案,而如果剩余数的出现次数都是$2$的话则无解。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 110; 5 6 vector<int> p[N]; 7 8 int main() { 9 int n; 10 cin >> n; 11 for (int i = 0; i < n; i++) { 12 int x; 13 cin >> x; 14 p[x].push_back(i); 15 } 16 17 int cnt = 0; 18 for (int i = 0; i < N; i++) { 19 if (p[i].size() == 1) cnt++; // 统计出现次数为1的数的个数 20 } 21 22 string ret(n, 'A'); // 初始化每个数都在集合A中 23 for (int i = 0, k = 0; i < N; i++) { 24 if (p[i].size() == 1 && k < cnt >> 1) { // 前k/2个数放到集合B中,如果cnt是奇数那么最后集合B的超级数比A少1 25 ret[p[i][0]] = 'B'; 26 k++; 27 } 28 } 29 30 bool flag = true; 31 if (cnt & 1) { // 超级数的个数为奇数 32 flag = false; 33 for (int i = 0; i < N; i++) { 34 if (p[i].size() > 2) { // 找到某个数的出现次数大于2 35 ret[p[i][0]] = 'B'; // 取第一个数放到集合B中,剩余的都放到集合A 36 flag = true; 37 break; 38 } 39 } 40 } 41 42 if (flag) cout << "YES/n" << ret; 43 else cout << "NO"; 44 45 return 0; 46 }
参考资料
AcWing 4608. 整数分组(AcWing杯 – 周赛):https://www.acwing.com/video/4274/
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/282632.html