Codeforces Round #697
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号女生)。
为了方便描述,现自己写一个样例如下:
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;
}