Panasonic Programming Contest (AtCoder Beginner Contest 195) A~E 题解

A - Health M Death

题目大意

有一位魔术师,他正在打一个血量为$H$?的怪兽。
当怪兽的血量是$M$的倍数时,魔术师能打败怪兽。
魔术师能打败怪兽吗?

$1\le M,H\le 1000$

输入格式

$M~H$

输出格式

如果魔术师能打败怪兽,输出Yes;如果不能,输出No

样例

$M$ $H$ 输出
$10$ $120$ Yes
$10$ $125$ No

分析

只需判断$H$是否是$M$的倍数即可。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <cstdio>
using namespace std;

int main()
{
	int m, h;
	scanf("%d%d", &m, &h);
	puts(h % m == 0? "Yes": "No");
	return 0;
}

B - Many Oranges

题目大意

我们有很多橙子。每个橙子的重量在$A$克到$B$克之间(包含$A$、$B$克,可能为小数)。
这些橙子的总重量为$W$千克
找到橙子最少和最多的数量。

$1\le A\le B\le 1000$
$1\le W\le 1000$

输入格式

$A~B~W$

输出格式

输出橙子最少和最多的数量,用一个空格隔开;如果数据不合法,输出UNSATISFIABLE

样例

$A$ $B$ $W$ 输出
$100$ $200$ $2$ $10~20$
$120$ $150$ $2$ $14~16$
$300$ $333$ $1$ UNSATISFIABLE

分析

如果要得到最小的结果,那么每个橙子的单价必定要取最大值。所以,我们设$min=\lceil\frac WB\rceil$。
同理,如果要得到最大的结果,那么每个橙子的单价必定要取最小值。所以,我们设$max=\lfloor\frac WA\rfloor$。
计算完成后,如果$min > max$,说明数据不合法;否则,输出$min$和$max$。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <cstdio>
using namespace std;

int main()
{
	int a, b, w;
	scanf("%d%d%d", &a, &b, &w);
	w *= 1000;
	int min = w % b == 0? w / b: w / b + 1;
	int max = w / a;
	if(min > max) puts("UNSATISFIABLE");
	else printf("%d %d\n", min, max);
	return 0;
}

C - Comma

题目大意

我们写一个整数时,可以从右开始每隔三位写一个逗号。如,$1234567$写作1,234,567、$777$直接写作777
如果我们写下$1$到$N$之间的所有整数,一共要用多少个逗号?

$1\le N\le 10^{15}$

输入格式

$N$

输出格式

输出总共需要的逗号的数量。

样例

$N$ 输出
$1010$ $11$
$27182818284590$ $107730272137364$

分析

我们可以按位置数逗号的数量。首先,在从右往左数的第一个逗号的位置,只要大于$1000$的数都需要写逗号。以此类推,在从右往左数的第$N$个逗号的位置,只要大于$1000^N$的数都需要写逗号。这样,我们就可以通过上述算法写出代码了。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <cstdio>
using namespace std;

typedef long long LL;

int main()
{
	LL n, ans = 0LL;
	scanf("%lld", &n);
	for(LL p=1000LL; p<=n; p*=1000LL)
		ans += n - p + 1;
	printf("%lld\n", ans);
	return 0;
}

D - Shipping Center

题目大意

我们有$N$个包裹(包裹$1$,……,包裹$N$)和$M$个盒子(盒子$1$,……,盒子$N$)。
第$i$个包裹的大小和价值分别是$W_i$和$V_i$。
第$i$个盒子最多只能装一个大小为$X_i$的包裹。
给你$Q$组询问,每组包含两个整数$L$和$R$,请回答下列问题:

  • 在这$M$个盒子中,盒子$L,L+1,\dots,R$暂时不可用。请把包裹放进剩余的盒子(不一定要全放)并输出最大可能的总价值。

$1\le N,M,Q\le 50$
$1\le W_i,V_i,X_i\le 10^6$
$1\le L\le R\le M$

输入格式

$N~M~Q$
$W_1~V_1$
$\vdots$
$W_N~V_N$
$X_1~\dots~X_M$
$L_1~R_1$
$\vdots$
$L_Q~R_Q$

输出格式

输出$Q$行。第$i$行应该包含$L_i$和$R_i$这个询问对应的答案。

样例

样例输入

1
2
3
4
5
6
7
8
3 4 3
1 9
5 3
7 8
1 8 6 9
4 4
1 4
1 3

样例输出

1
2
3
20
0
9

分析

这道题看似很像背包问题,其实不然。我们只需升序排序数组$X$后,再按顺序贪心地为每个盒子选择它能拿到的价值最高的包裹即可。总时间复杂度为$\mathcal O(NMQ)$。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <cstdio>
#include <algorithm>
#define maxn 55
using namespace std;

typedef pair<int, int> pii;

pii bags[maxn], boxes[maxn];
bool taken[maxn];

int main()
{
	int n, m, q;
	scanf("%d%d%d", &n, &m, &q);
	for(int i=0; i<n; i++)
		scanf("%d%d", &bags[i].second, &bags[i].first);
	sort(bags, bags + n, greater<pii>());
	for(int i=0; i<m; i++)
		scanf("%d", &boxes[i].first), boxes[i].second = i;
	sort(boxes, boxes + m);
	while(q--)
	{
		int l, r, ans = 0;
		scanf("%d%d", &l, &r);
		l --, r --;
		fill(taken, taken + n, false);
		for(int i=0; i<m; i++)
		{
			auto [size, idx] = boxes[i];
			if(idx < l || idx > r)
			{
				int j = 0;
				for(; j<n; j++)
					if(!taken[j] && bags[j].second <= size)
						break;
				if(j < n)
					ans += bags[j].first, taken[j] = true;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

E - Lucky 7 Battle

题目大意

我们有一个长度为$N$、由数字0~9组成的字符串$S$,和一个长度同样为$N$、由AT组成的字符串$X$。
Takahashi和Aoki要用这两个字符串玩一个$N$轮的游戏。最开始,他们有一个空的字符串$T$。在第$i$轮($1\le i\le N$),他们要做下列事情:

  • 如果$X_i$为A,Aoki执行下面的操作;如果$X_i$为T,则Takahashi执行下面的操作:
  • 将$S_i$或者0加到$T$的后面。

在$N$个操作之后,$T$会变成一个数字0~9组成的字符串。如果我们把它看成一个十进制数(去掉前导$0$),那么如果这个数为$7$的倍数,则Takahashi胜;相反,如果这个数不为$7$的倍数,则Aoki胜。

判断当两个人都按照最优操作进行游戏时,谁会赢。

$1\le N\le 10^5$
$|S|=|X|=N$

输入格式

$N$
$S$
$X$

输出格式

输出胜者的名字(Takahashi或者Aoki)。

样例

略,请自行前往AtCoder查看

分析

这题首先很容易想到使用搜索。我们定义$\mathrm{winner}(i,r)=~$在第$i$轮$T\bmod7=r$最终的赢家。
我们会发现,由于$r$只有$0$~$6$,计算重复率较高,所以这题可以使用记忆化搜索来解决。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <cstdio>
#include <cstring>
#define AO 0
#define TA 1
#define maxn 200005
using namespace std;

char s[maxn], x[maxn];
int n, dp[maxn][7];

int winner(int i, int r)
{
	if(dp[i][r] != -1) return dp[i][r];
	if(i >= n) return dp[i][r] = r == 0;
	if(winner(i + 1, 10 * r % 7) == TA)
	{
		if(x[i] == 'T')
			return dp[i][r] = TA;
	}
	else if(x[i] == 'A') return dp[i][r] = AO;
	if(winner(i + 1, (10 * r + s[i] - '0') % 7) == TA)
	{
		if(x[i] == 'T')
			return dp[i][r] = TA;
	}
	else if(x[i] == 'A') return dp[i][r] = AO;
	return dp[i][r] = x[i] == 'A';
}

int main()
{
	scanf("%d%s%s", &n, s, x);
	memset(dp, -1, sizeof(dp));
	puts(winner(0, 0) == TA? "Takahashi": "Aoki");
	return 0;
}
使用 Hugo 构建
主题 StackJimmy 设计