Codeforces Round #697 (Div. 3) (A B C E题解)

A.Odd Divisor

原题链接:https://codeforces.com/contest/1475/problem/A

题意
对于每一个 n ,判断是否存在大于 1 的奇数除数,如果有输出YES,反之输出NO。

思路
① 如果 n 是奇数,那么大于 1 的奇数除数可以是它本身;
② 如果 n 是偶数,那么只有 n 是 2 的整数次幂的时候,才不存在大于 1 的奇数除数。
因为所有大于 1 的正整数都可以拆分成若干个质数相乘,质数里面只有 2 是偶数,所以如果所有质因数只有 2 那么输出 NO;反之输出 YES。

#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
#define ll long long 
const int N = 10000; 

int main() {
    
    
	int t;
	scanf("%d", &t);
	while (t --) {
    
    
		ll n;
		scanf("%lld", &n);
		if ((n & 1) == 0) {
    
      // n 是偶数
			while (n % 2 == 0) n /= 2;
			if (n == 1) printf("NO\n");
			else printf("YES\n");
		}
		else printf("YES\n");
	}
	return 0;
}

B.New Year’s Number

原题链接:https://codeforces.com/contest/1475/problem/B

题意
对于每一个 n ,如果能被表示为 n == a * 2020 + b * 2021 (a 、b为非负数),那么输出YES,反之输出NO。

思路
先求出 n 需要由几个数构成: a + b = n / 2020
再求一下溢出部分,即需要2021的 1 填补的部分 :x = n % 2020
那么 x 即为需要有 x 个2021,所以如果 x <= (a + b),那么输出 YES,反之输出 NO。

//B
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
#define ll long long 
const int N = 10000; 

int main() {
    
    
	int t;
	scanf("%d", &t);
	while (t --) {
    
    
		int n;
		scanf("%d", &n);
		int a = n / 2020;
		int b = n % 2020;
		if (b > a) printf("NO\n");
		else printf("YES\n");
	} 
	return 0;
}

C.Ball in Berland

原题链接:https://codeforces.com/contest/1475/problem/C

题意
一个班有 a 个男生,b 个女生,k 支一男一女的队伍。k 支队伍里面同一个男生可能和多个女生组队,现要从该班随机抽出 2 支队伍参加舞会,问有多少种取法(两支队伍里,不能是同一个男生或女生)?

思路
首先要分清楚输入的组队方式是竖着看,比如说第一个样例里的:
3 4 4
1 1 2 3
2 3 2 4
分别表示:a = 3 b = 4 k = 4,且组队方式是(1号男生,2号女生)(1号男生,3号女生)(2号男生,2号女生)(3号男生,4号女生)。

扫描二维码关注公众号,回复: 12878167 查看本文章

为了方便描述,现自己写一个样例如下:
7 6 8
2 2 2 3 3 5 6 7
1 2 3 1 6 6 6 6
即:该班中一共有 7 个男生、6 个女生,8 支可能队伍。

那么如何计算才不会重复呢?
我们可以发现,因为最终也只是挑出两支队伍,假如先不考虑女生会重复的情况,只考虑男生不会重复,那么可以看出在这八只队伍里面,全班 7 个男生只有 2、3、5、6、7 这 5 个男生参与组队,那么(2 ,1)就可以和(3,x)、(5 ,x)、(6 ,x)、(7 ,x)成为最终的两支队伍,且由于 (2 , x)一共有 3 种组队方式,所以如果最终挑出来的两支队伍里有 2 号男生,那么一共有 (包含2号男生的队伍数目)* (还没被算过的队伍数) = 3 * 5 = 15 种搭配方式
以此类推如果最终的两支队伍有 3 号男生,那么搭配方式的种数 = 2 * 3 = 6(这里不再重复计算(2 ,x)和(3 , x)搭配)。
故而,如果不考虑女生重复的情况,只考虑男生不重复,那么搭配总数 = 3 * 5 + 2 * 3 + 1 * 2 + 1 * 1 = 15 + 6 + 2 + 1 = 24 种(最后的(7 ,x)不需要计算)。

那么现在剩下的工作就是剔除女生重复的种数。
对于1 2 3 1 6 6 6 6重新排一下序: 1 1 2 3 6 6 6 6,那么重复的如图:在这里插入图片描述
所以女生重复的种数就是1 + (3 + 2 + 1)= 7。
可以发现,对于有 2 支队伍有 1 号女生,那么重复的种数就是以 n = 2 - 1,a1 = 1,d = 1 的等差数列的前 n 项和

故而最终答案为 24 - 7 = 17种。
其他情况以此类推。

#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
#define ll long long 
const int N = 200020;
int arr[N];
int brr[N]; 

int main() {
    
    
	int t;
	scanf("%d", &t);
	while (t --) {
    
    
		memset(arr, 0, sizeof(arr));
		memset(brr, 0, sizeof(brr));
		ll a, b , k;
		scanf("%lld %lld %lld", &a, &b, &k);
		for (int i = 0; i < k; ++ i) {
    
    
			int a;
			scanf("%d", &a);
			++ arr[a];
		}
		for (int i = 0; i < k; ++ i) {
    
    
			int a;
			scanf("%d", &a);
			++ brr[a];
		}

		ll ans = 0, sum = k;
		for (int i = 1; i <= a; ++ i) {
    
    
			sum -= arr[i];
			if (sum == 0) break;
			ans += (arr[i] * sum);
		}
		for (int i = 1; i <= b; ++ i) {
    
    
			if (brr[i])  ans -= (brr[i] - 1) * brr[i] / 2;
		}
		printf("%lld\n", ans);
	} 
	return 0;
} 

E. Advertising Agency

原题链接:https://codeforces.com/contest/1475/problem/E

题意

一共有 n 个博主,每个博主至少有一名粉丝,但是现在经费有限,只能和其中 k 个博主合作。
问在同样获得最大粉丝数的前提下,一共有多少种不同的选择方案?
(只有两个方案中,有至少一名博主不同就视为不同方案)

思路
因为题目要求了,所有的方案都必须在获得最大粉丝数的前提下,那么假如现在一共有 10 位博主,每一位博主的粉丝数分别为 34、34、67、90、10、34、34、78、23、34,现只能和其中 k = 5 位博主合作。

我们可以先对粉丝数目排一下序得到:10、23、34、34、34、34、34、67、78、90。
因为题目要求必须粉丝总数最大化,我们可以得到 67、78、90 这三位博主必选,剩下 2 个合作名额则在 5 位具有相同粉丝数34的博主中产生,所以选择方案一共有 C ( 2 5 ) \tbinom{ 2 }{ 5 } (52) 种。

综上,由于本题数据比较小,可以开一个book数组存下粉丝数量在 1 ~ 1000的博主数量,然后从后往前遍历找到临界的粉丝数的博主,再求一下组合数即为答案。

需要注意的是,由于求组合数时可能会溢出,所以先打一个表,到时对于每一个样例直接查表table即可。
【tips:杨辉三角对应了组合数】
1
1 1
1 2 1
1 3 3 1
…………
对应了:
C ( 0 0 ) \tbinom{0}{0} (00)

C ( 0 1 ) \tbinom{0}{1} (10) C ( 1 1 ) \tbinom{1}{1} (11)

C ( 0 2 ) \tbinom{0}{2} (20) C ( 1 2 ) \tbinom{1}{2} (21) C ( 2 2 ) \tbinom{2}{2} (22)

C ( 0 3 ) \tbinom{0}{3} (30) C ( 1 3 ) \tbinom{1}{3} (31) C ( 2 3 ) \tbinom{2}{3} (32) C ( 3 3 ) \tbinom{3}{3} (33)

//E
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
#define ll signed long long  
const int N = 1020; 
int book[N];   //各粉丝数对应的博主数量
int mod = 1e9 + 7;

ll table[1020][1020];   //组合数

//借杨辉三角打表
void makeTable() {
    
    
	table[0][0] = 1;
	for (int i = 1; i <= 1002; ++ i) {
    
    
		int length = i + 1;
		for (int j = 0; j < length; ++ j) {
    
    
			if (j == 0) table[i][j] = table[i - 1][j];
			else table[i][j] = table[i - 1][j] + table[i - 1][j - 1];
			table[i][j] %= mod;
		}
	}
} 

int main() {
    
    
	makeTable();
	int t;
	scanf("%d", &t);
	while (t --) {
    
    
		ll n, k;
		scanf("%lld %lld", &n, &k);
		memset(book, 0, sizeof(book));   //记得置零
		for (int i = 0; i < n; ++ i) {
    
    
			int a;
			scanf("%d", &a);
			++ book[a];    //统计粉丝数量为 a 的博主有多少个
		}
		int i;
		for (i = 1000; i >= 0; -- i) {
    
    
			k -= book[i];
			if (k <= 0) {
    
    
				break;
			}
		}
		if (k == 0) printf("1\n");  //说明刚刚好,只有一种合作方式
		else {
    
    
			k += book[i];
			ll ans = table[book[i]][k];  //查表得组合数
			printf("%lld\n", ans % mod);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/CSDNWudanna/article/details/113210481