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