ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

整数分组

2022-08-28 09:32:48  阅读:182  来源: 互联网

标签:leq int 超级 整数 某个 分组 集合


整数分组

给定一个包含 $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$,分情况讨论:

  1. $2 \mid k$,那么两个集合每个都分$\frac{k}{2}$个就可以了,剩余数的出现次数都大于$1$,可以将他们全部放到$A$或$B$中。最后就可以实现两个集合的超级数的数量都是$\frac{k}{2}$。
  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/

标签:leq,int,超级,整数,某个,分组,集合
来源: https://www.cnblogs.com/onlyblues/p/16632241.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有