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\)的倍数即可。
代码
#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\)。
代码
#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\)的数都需要写逗号。这样,我们就可以通过上述算法写出代码了。
代码
#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\)这个询问对应的答案。
样例
样例输入
3 4 3
1 9
5 3
7 8
1 8 6 9
4 4
1 4
1 3
样例输出
20
0
9
分析
这道题看似很像背包问题,其实不然。我们只需升序排序数组\(X\)后,再按顺序贪心地为每个盒子选择它能拿到的价值最高的包裹即可。总时间复杂度为\(\mathcal O(NMQ)\)。
代码
#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\)、由A和T组成的字符串\(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\),计算重复率较高,所以这题可以使用记忆化搜索来解决。
代码
#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;
}

浙公网安备 33010602011771号