GoodCoder666的个人博客

AtCoder Beginner Contest 205 A~E 题解

2021-07-07 · 9 min read
C++ 算法竞赛

A - kcal

题目大意

我们有一种每100100毫升含有AA千卡热量的饮料。BB毫升的这种饮料含有多少千卡热量?

0A,B10000\le A, B\le 1000

输入格式

A BA~B

输出格式

输出BB毫升这种饮料包含的的千卡数。最大允许浮点数精度误差10610^{-6}

样例

AA BB 输出
4545 200200 9090
3737 450450 166.5166.5
00 10001000 00
5050 00 00

分析

废话不多说,答案就是AB100\frac{AB}{100}~

代码

#include <cstdio>
using namespace std;

int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
	a *= b;
	printf("%d.%d\n", a / 100, a % 100);
	return 0;
}

B - Permutation Check

题目大意

给定长度为NN的序列A=(A1,A2,,AN)A=(A_1,A_2,\dots,A_N)
判断AA是否为(1,2,,N)(1,2,\dots,N)的一种排列。

1AiN1031\le A_i\le N\le 10^3

输入格式

NN
A1 A2  ANA_1~A_2~\dots~A_N

输出格式

如果AA(1,2,,N)(1,2,\dots,N)的一种排列,输出Yes;否则,输出No

样例

样例输入1

5
3 1 2 4 5

样例输出1

Yes

(3,1,2,4,5)(3,1,2,4,5)(1,2,3,4,5)(1,2,3,4,5)的一种排列,所以我们输出Yes

样例输入2

6
3 1 4 1 5 2

样例输出2

No

(3,1,4,1,5,2)(3,1,4,1,5,2)不是(1,2,3,4,5,6)(1,2,3,4,5,6)的一种排列,所以我们输出No

样例输入3

3
1 2 3

样例输出3

Yes

样例输入4

1
1

样例输出4

Yes

分析

由于题目保证1AiN1\le A_i\le N,所以(1,2,,N)(1,2,\dots,N)的一种排列AA定义如下:

  • AA11NN每个数字不重复出现。

因此,我们可以用数组记录每个数字是否出现,所以总时间复杂度为O(n)\mathcal O(n)

代码

#include <cstdio>
#define maxn 1005
using namespace std;

bool used[maxn];

int main()
{
	int n;
	scanf("%d", &n);
	for(int i=0; i<n; i++)
	{
		int a;
		scanf("%d", &a);
		if(used[a])
		{
			puts("No");
			return 0;
		}
		used[a] = true;
	}
	puts("Yes");
	return 0;
}

C - POW

题目大意

给定三个整数A,B,CA,B,C,判断ACA^CBCB^C哪个更大。

109A,B109-10^9\le A,B\le 10^9
1C1091\le C\le 10^9

输入格式

A B CA~B~C

输出格式

本题分如下三种情况输出:

  • 如果AC<BCA^C<B^C,输出<
  • 如果AC>BCA^C>B^C,输出>
  • 如果AC=BCA^C=B^C,输出=

样例

AA BB CC 输出
33 22 44 >
7-7 77 22 =
8-8 66 33 <

分析

首先,由于负负得正(a)2=a2(-a)^2=a^2
这样,我们可以根据奇偶性得出,如果nn为偶数,(a)n=an(-a)^n=a^n;但如果nn为奇数,则(a)n=(an)(-a)^n=-(a^n)
因此,我们只需判断如果CC为偶数,将AA替换为A|A|,再将BB替换为B|B|
最后,AABB的大小关系就是ACA^CBCB^C的大小关系。

代码

#include <cstdio>
using namespace std;

int main()
{
	int a, b, c;
	scanf("%d%d%d", &a, &b, &c);
	if(!(c & 1))
	{
		if(a < 0) a = -a;
		if(b < 0) b = -b;
	}
	puts(a < b? "<": a > b? ">": "=");
	return 0;
}

D - Kth Excluded

题目大意

给定长度为NN的正整数序列A=(A1,A2,,AN)A=(A_1,A_2,\dots,A_N)QQ次查询。
在第ii次查询中,给定正整数KiK_i,求第KiK_i小的不在AA中的正整数。

1N,Q1051\le N,Q\le 10^5
1A1<A2<<AN10181\le A_1<A_2<\dots<A_N\le10^{18}
1Ki10181\le K_i\le 10^{18}

输入格式

N QN~Q
A1 A2  ANA_1~A_2~\dots~A_N
K1K_1
K2K_2
\hspace{5pt}\vdots
KNK_N

输出格式

输出QQ行。第ii行应该包含第KiK_i小的不在AA中的正整数。

样例

样例输入1

4 3
3 5 6 7
2
5
3

样例输出1

2
9
4

不在AA中的正整数有1,2,4,8,9,10,11,1,2,4,8,9,10,11,\dots,其中有:

  • 22小的22
  • 55小的99
  • 33小的44

因此,我们应该依次输出294

样例输入2

5 2
1 2 3 4 5
1
10

样例输出2

6
15

分析

本题我们可以先预处理出AA中每个元素比它小的元素的数量,再二分查找即可。

代码

#include <cstdio>
#include <algorithm>
#define maxn 100005
using namespace std;

using LL = long long;
LL a[maxn];

int main()
{
	int n, q;
	scanf("%d%d", &n, &q);
	for(int i=0; i<n; i++)
	{
		scanf("%lld", a + i);
		a[i] -= i;
	}
	while(q--)
	{
		LL k;
		scanf("%lld", &k);
		printf("%lld\n", k + (upper_bound(a, a + n, k) - a));
	}
	return 0;
}

E - White and Black Balls

题目大意

有多少种排列NN个白球和MM个黑球的方法使得下列条件成立?

  • 对于每个ii (1iN+M1\le i\le N+M),设wiw_ibib_i分别是最左边ii个球中白球和黑球的数量,wibi+Kw_i\le b_i+K成立。

答案对(109+7)(10^9+7)取模。

0N,M1060\le N,M\le10^6
1N+M1\le N+M
0KN0\le K\le N

输入格式

N M KN~M~K

输出格式

输出答案,对(109+7)(10^9+7)取模。

样例

NN MM KK 输出
22 33 11 99
11 00 00 00
10000001000000 10000001000000 10000001000000 192151600192151600

分析

首先,本题中合法排列数就是如下符合任意yx+Ky\le x+K(0,0)(M,N)(0,0)\to(M,N)最短路径的数量:
路径解释图

由此可见,如果N>M+KN>M+K(即终点超出限制),答案一定为00
我们还可以发现,如果没有yx+Ky\le x+K这个限制,答案为(N+MN)\binom{N + M}{N}
我们再考虑不合法的路径数,数量为(N+MM+K+1)\binom{N + M}{M + K + 1}
因此,答案为(N+MN)(N+MM+K+1)\binom{N + M}{N}-\binom{N + M}{M + K + 1}

代码

这里用AtCoder Library好像比较方便唉~

#include <iostream>
#include <atcoder/modint>
using namespace std;

using modint = atcoder::modint1000000007;

modint f(int n, int m)
{
	if(n < 0 || m < 0)
		return 0;
	modint ret = 1;
	for(int i=1; i<=m; i++)
		ret = ret * (n + i) / i;
	return ret;
}

int main()
{
	int n, m, k;
	scanf("%d%d%d", &n, &m, &k);
	if(n > m + k) puts("0");
	else printf("%d\n", (f(n, m) - f(n - k - 1, m + k + 1)).val());
	return 0;
}