[题解]Codeforces Round #709 (Div. 1, based on Technocup 2021 Final Round) - A. Basic Diplomacy

【题目】

A. Basic Diplomacy

【描述】

Aleksey有n个朋友,有一个m天的假期,每天都需要一个朋友来陪他。给出每天有空的朋友的编号,要求同一个朋友来的天数不能超过m/2上取整。求是否有一个朋友到访的方案,没有输出“NO”,有输出“YES”并输出任意一种方案。

数据范围:1<=n,m<=100000,保证每天至少有一个朋友有空,共t组数据,1<=t<=10000

【思路】

这道题只要注意到“同一个朋友来的天数不能超过m/2上取整”的要求就很简单了。

首先,由于总天数是m,所以随意一种方案,最多就只有一个朋友来的天数超过了这个上界,我们不妨称这个来太多次的朋友为zyy;于是我们只需要让zyy少来几次就行了。

于是我们遍历zyy具体来的那些天,尝试替换成当天有空的别的朋友来;只需要替换到zyy来的天数恰好为m/2上取整就可以不再替换了。

然后我们来看看,如果上述替换能够成功(就是能够替换到zyy来的天数恰好为m/2上取整),新的方案能否满足要求?答案是肯定的。因为新方案中zyy一共来了m/2上取整天,剩余的m-(m/2上取整)天<=m/2上取整天,换言之即使剩余的每一天都是同一个人来,也是符合要求的。

而如果上述替换不能成功(就是无论如何调整,zyy来的天数都要多于m/2上取整),那么很显然没有符合要求的方案。

现在,我们来考虑替换方法。根据上述分析,聪明的读者已经发现,只要在zyy来的那些天里,找到足够的天数同时有别的朋友也有空就行了。于是我们遍历zyy具体来的那些天,一旦某一天有别的朋友有空,我们就让别的朋友替换zyy在那一天来,直到zyy来的天数恰好为m/2上取整,或者替换不成功;由于本题的上界是“不能超过m/2上取整”,保证了不会同时出现超限的两个朋友,也保证了不会让一个朋友符合要求而导致另一个朋友超限,于是遍历的顺序不会导致错误(所以顺序遍历就ok啦),替换成的别的朋友的选择也可以很随意(只要不是zyy就ok啦)。

以上就是本题的解题思路。但是,聪明的读者或许发现了一个小猫腻:只需记住每天有最多哪两个朋友有空就可以啦!这实际上也是由上界“不能超过m/2上取整”带来的小性质。

思路说清楚了,实现很简单,就不赘述了,不清楚可以参考一下下面的代码。每组的复杂度为O(m*n),也就是读数据的复杂度了。

(老年人zyy一开始没注意到上界“不能超过m/2上取整”的性质,一开始想贪心,觉得不对,又想要不还是搜索+剪枝吧,写到一半才发现这个性质,果然是脑子不行了……)

【我的实现】

复杂度:每组数据O(m*n)

  1 //#define _CRT_SECURE_NO_WARNINGS
  2 
  3 #include <iostream>
  4 #include <cstdio>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <string>
  8 #include <cstring>
  9 #include <cstdlib>
 10 #include <vector>
 11 #include <list>
 12 #include <map>
 13 #include <queue>
 14 #include <stack>
 15 #include <set>
 16 
 17 #define PRO 'A'
 18 //#define PRO 'B'
 19 //#define PRO 'C'
 20 //#define PRO 'D'
 21 //#define PRO 'E'
 22 //#define PRO 'F'
 23 //#define PRO 'G'
 24 //#define PRO 'H'
 25 //#define PRO 'I'
 26 
 27 
 28 using namespace std;
 29 
 30 #if (PRO == 'A')
 31 
 32 #define N 100000
 33 #define M 100000
 34 
 35 int cnt[N];
 36 int fri[M][2], ans[M];
 37 
 38 
 39 #endif // (PRO == 'A')
 40 
 41 #if (PRO == 'B')
 42 
 43 #endif // (PRO == 'B')
 44 
 45 #if (PRO == 'C')
 46 
 47 #endif // (PRO == 'C')
 48 
 49 #if (PRO == 'D')
 50 
 51 #endif // (PRO == 'D')
 52 
 53 #if (PRO == 'E')
 54 
 55 #endif // (PRO == 'E')
 56 
 57 #if (PRO == 'F')
 58 
 59 #endif // (PRO == 'F')
 60 
 61 #if (PRO == 'G')
 62 
 63 #endif // (PRO == 'G')
 64 
 65 #if (PRO == 'H')
 66 
 67 #endif // (PRO == 'H')
 68 
 69 #if (PRO == 'I')
 70 
 71 #endif // (PRO == 'I')
 72 
 73 
 74 int main()
 75 {
 76 #if (PRO == 'A')
 77     int T;
 78     int n, m;
 79     int i, j;
 80     int tmp, tmp2;
 81     int fri_num;
 82     
 83     scanf("%d", &T);
 84     while (T--) {
 85         fri_num = -1;
 86         memset(cnt, 0, sizeof(cnt));
 87         scanf("%d%d", &n, &m);
 88         for (i = 0; i < m; i++) {
 89             scanf("%d", &tmp);
 90             if (tmp == 1) {
 91                 scanf("%d", &fri[i][0]);
 92                 fri[i][1] = -1;
 93             }
 94             else {
 95                 scanf("%d%d", &fri[i][0], &fri[i][1]);
 96                 for (j = 2; j < tmp; j++) {
 97                     scanf("%d", &tmp2);
 98                 }
 99             }
100             ans[i] = fri[i][0];
101             cnt[ans[i]]++;
102             if (cnt[ans[i]] > (m + 1) / 2) {
103                 fri_num = ans[i];
104             }
105         }
106         if (fri_num != -1) {
107             for (i = 0; i < m; i++) {
108                 if (ans[i] == fri_num && fri[i][1] != -1) {
109                     ans[i] = fri[i][1];
110                     cnt[fri_num]--;
111                     cnt[fri[i][1]]++;
112                     if (cnt[fri_num] <= (m + 1) / 2) {
113                         break;
114                     }
115                 }
116             }
117         }
118         if (fri_num != -1 && cnt[fri_num] > (m + 1) / 2) {
119             printf("NO\n");
120         }
121         else {
122             printf("YES\n");
123             for (i = 0; i < m; i++) {
124                 printf("%d ", ans[i]);
125             }
126             printf("\n");
127         }
128     }
129     //cout << "Hello World!\n";
130 #endif // (PRO == 'A')
131 
132 #if (PRO == 'B')
133 
134     //cout << "Hello World!\n";
135 #endif // (PRO == 'B')
136 
137 #if (PRO == 'C')
138 
139     //cout << "Hello World!\n";
140 #endif // (PRO == 'C')
141 
142 #if (PRO == 'D')
143 
144     //cout << "Hello World!\n";
145 #endif // (PRO == 'D')
146 
147 #if (PRO == 'E')
148 
149     //cout << "Hello World!\n";
150 #endif // (PRO == 'E')
151 
152 #if (PRO == 'F')
153 
154     //cout << "Hello World!\n";
155 #endif // (PRO == 'F')
156 
157 #if (PRO == 'G')
158 
159     //cout << "Hello World!\n";
160 #endif // (PRO == 'G')
161 
162 #if (PRO == 'H')
163 
164 
165 #endif // (PRO == 'H')
166 
167 #if (PRO == 'I')
168 
169     //cout << "Hello World!\n";
170 #endif // (PRO == 'I')
171 
172 
173     //cout << "Hello World!\n";
174     return 0;
175 }
View Code

【评测结果】

 

 

ps. 几百年没有登过cf了。最近不太开心,恰巧清理邮箱时看到一大堆cf的邮件,就登上去看了看,密码竟然还记得(不像博客园,试了好几次之后只好找回密码,还被迫绑定了手机号)。随意点开了之前的一场div1的比赛,从踌躇满志到无奈苦笑,搞了好久才搞出来第一题,老年人的思维复建过程令人羞愧,心想还好没有鲁莽地注册比赛,否则本就不高的排名怕是要掉到姥姥家了。感觉这道题有些意思,所以来记录一下(虽然想来这样简单的题目的题解大概是不会有人看的吧)。讲不清自己是怎么一步一步选择了现在的生活状态,虽说谈不上不喜欢,但似乎确实没有过以前搞竞赛时A题的快乐了,取得的成绩从各种意义上也算不上好看,也许真的就是不适合吧。下次更新不知道又是什么时候了,希望下次能够开心一点。

posted @ 2021-04-04 00:36  zyy是一只超级大沙茶  阅读(65)  评论(0编辑  收藏  举报