Codeforces Round #545 B. Circus
题面:
题目描述:
马戏团中一共有N个人(N是偶数),有的人会扮演小丑,有的人会表演杂技。给出每个人会什么,然后按照下列规则把这些人分成两组:
- 每个人只能在其中一组
- 两个组的人数相等(也就是把这些人分半)
- 在第一个组会扮演小丑的人的数量,等于在第二个组会表演杂技的数量
输出:被分配在第一个组的人(每个人对应一个下标,输出相应的下标)
题目分析:
前言:这道题刚开始还以为是贪心解决,但是由于博主太渣😭,用贪心过不了(这里我简单说一下我的贪心思路:把:只会扮演小丑的人放在第二组,只会表演杂技的人放在第一组,然后分类讨论??)。看了官方题解后,竟然是用数学解决→_→。
首先,根据题意,我们可以知道一共有四种人:
1.只会扮演小丑的人2.只会表演杂技的人3.既会扮演小丑,又会表演杂技的人4.什么都不会的人
这里我们先要理解好题意:
对于第一种人,如果放在第一组,那么在第一个组会扮演小丑的人的数量就会+1。第一种人可不可以放在第二组?可以,注意到题目只是说要符合数量相等,而没有强制要求第一组的人一定要会扮演小丑,第二组的人一定要会表演杂技。所以第一种人可以放在第二组,只是放在第二组没有“贡献”(这里的“贡献”:在第二个组会表演杂技的数量+1)而已。对于其他的人都有类似的情况。
既然是这样,那么岂不是可以直接贪心做出来?不过,这里我们不研讨贪心的做法,这个可以自己回去想一想。我们可以再看看题目的数据:2≤n≤5000,所以有什么更简单直接暴力的方法???
的确是有:根据给出的数据,我们可以很快统计出四种人的人数,我们可以用一些变量表示:
第一种人:only_c第二种人:only_a第三种人:both_ca第四种人:not_ca
统计完后,我们假设在第一组这四种人的数量:
第一种人:c_num第二种人:a_num第三种人:b_num第四种人:n_num
由题易得两个等式:
c_num + a_num + b_num + n_num == n / 2 (第一组人的数量)c_num + b_num == (only_a - a_num) + (both_ca - b_num) (第一个组会扮演小丑的人的数量,等于第二个组会表演杂技的数量)
这里有四个未知量(c_num, a_num, b_num, n_num),两个方程(等式),所以怎样解方程?
我们知道,像这种情况,方程没有唯一解。但是有多种解啊,所以我们只要求出一个符合题意的方程的解就可以了,那么怎么求?
假如我们确定了四个未知量的其中两个未知量,这时就变成了简单的二元方程了,然后另外两个未知量是不是就解出来了?我们可以这样化简方程:(这里我为了方便选择了c_num和b_num作为自由变量,选其他作为自由变量也没有影响)
c_num = c_numa_num = only_a + both_ca - 2 * b_num - c_numb_num = b_numn_num = n / 2 - only_a - both_ca + b_num
写成这个样子,是不是每个变量都可以用c_num和b_num来表示?接下来就是要确定c_num和b_num要取什么值。
c_num范围:[0, only_c],b_num范围:[0, both_ca]。那么是不是意味着随便取c_num和b_num的值,比如直接取c_num = 0,b_num = 0?当然不是,c_num的值和b_num的值除了要在范围内,还要满足它们的解(a_num和n_num)合法,也就是说,带入c_num和b_num的值进方程后,解出来的a_num范围[0, only_a],n_num范围[0, not_ca]。因此,我们暴力枚举c_num和b_num的值产生的所有可能,看哪些解是合法的,最后答案取合法的解就行了。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 char clo[5005], acr[5005]; 4 int type[5005]; 5 int n; 6 int only_c, only_a, both_ca, not_ca; 7 8 bool in(int x, int l, int r){ 9 if(l <= x && x <= r) return true; 10 return false; 11 } 12 13 int main(){ 14 scanf("%d", &n); 15 scanf("%s%s", clo, acr); 16 17 for(int i = 0; i < n; i++){ 18 if(clo[i] == '1' && acr[i] == '0') only_c++, type[i] = 1; 19 if(clo[i] == '0' && acr[i] == '1') only_a++, type[i] = 2; 20 if(clo[i] == '1' && acr[i] == '1') both_ca++, type[i] = 3; 21 if(clo[i] == '0' && acr[i] == '0') not_ca++, type[i] = 4; 22 } 23 24 int c_num, a_num, b_num, n_num; 25 int sus = 0; 26 for(c_num = 0; c_num <= only_c; c_num++){ 27 for(b_num = 0; b_num <= both_ca; b_num++){ 28 a_num = only_a + both_ca - 2 * b_num - c_num; 29 n_num = n / 2 - only_a - both_ca + b_num; 30 if(in(a_num, 0, only_a) && in(n_num, 0, not_ca)){ 31 sus = 1; 32 break; 33 } 34 } 35 if(sus) break; 36 } 37 38 if(sus == 0) { 39 printf("-1"); 40 return 0; 41 } 42 43 int c_cnt, a_cnt, b_cnt, n_cnt; 44 c_cnt = a_cnt = b_cnt = n_cnt = 0; 45 for(int i = 0; i < n; i++){ 46 sus = 0; 47 if(type[i] == 1 && c_cnt < c_num) 48 c_cnt++, sus = 1; 49 if(type[i] == 2 && a_cnt < a_num) 50 a_cnt++, sus = 1; 51 if(type[i] == 3 && b_cnt < b_num) 52 b_cnt++, sus = 1; 53 if(type[i] == 4 && n_cnt < n_num) 54 n_cnt++, sus = 1; 55 56 if(sus) printf("%d ", i+1); 57 } 58 return 0; 59 }
不行,这个写的太丑,再继续写:
1 #include <bits/stdc++.h> 2 using namespace std; 3 char c[5005], a[5005]; 4 int only_c, only_a, both_ca, not_ca; 5 int st[10][5005]; //栈? 6 int num[10]; //存n_num(num[0]),a_num(num[1]),c_num(num[2]),b_num(num[3]) 7 int n; 8 9 bool in(int x, int l, int r){ 10 if(l <= x && x <= r) return true; 11 return false; 12 } 13 14 int main(){ 15 scanf("%d", &n); 16 scanf("%s%s", c+1, a+1); 17 for(int i = 1; i <= n; i++){ 18 //预处理一下 19 c[i] -= '0', a[i] -= '0'; 20 } 21 22 int t; 23 for(int i = 1; i <= n; i++){ 24 t = c[i]*2 + a[i]; //二进制思想?? 25 if(t == 0) st[t][not_ca++] = i; 26 if(t == 1) st[t][only_a++] = i; 27 if(t == 2) st[t][only_c++] = i; 28 if(t == 3) st[t][both_ca++] = i; 29 } 30 31 int sus = 0; 32 for(num[2] = 0; num[2] <= only_c; num[2]++){ 33 for(num[3] = 0; num[3] <= both_ca; num[3]++){ 34 num[1] = only_a + both_ca - 2*num[3] - num[2]; 35 num[0] = n/2 - (num[1]+num[2]+num[3]); //算出num[1]后可以直接这样算num[0] 36 if(in(num[0], 0, not_ca) && in(num[1], 0, only_a)){ 37 sus = 1; 38 break; 39 } 40 } 41 if(sus) break; 42 } 43 44 //找不到解 45 if(sus == 0) { 46 printf("-1"); 47 return 0; 48 } 49 50 //输出答案 51 for(int i = 0; i < 4; i++){ 52 for(int j = 0; j < num[i]; j++){ 53 printf("%d ", st[i][j]); 54 } 55 } 56 return 0; 57 }