概述
ABC201/Mynavi2021 A~E
- [A - Tiny Arithmetic Sequence](https://atcoder.jp/contests/abc201/tasks/abc201_a)
- 题目大意
- 输入格式
- 输出格式
- 样例
- 分析
- 代码
- [B - Do you know the second highest mountain?](https://atcoder.jp/contests/abc201/tasks/abc201_b)
- 题目大意
- 输入格式
- 输出格式
- 样例
- 样例输入1
- 样例输出1
- 样例输入2
- 样例输出2
- 样例输入3
- 样例输出3
- 分析
- 代码
- [C - Secret Number](https://atcoder.jp/contests/abc201/tasks/abc201_c)
- 题目大意
- 输入格式
- 输出格式
- 样例
- 分析
- 代码
- [D - Game in Momotetsu World](https://atcoder.jp/contests/abc201/tasks/abc201_d)
- 题目大意
- 输入格式
- 输出格式
- 样例
- 分析
- 代码
- [E - Xor Distances](https://atcoder.jp/contests/abc201/tasks/abc201_e)
- 题目大意
- 输入格式
- 输出格式
- 样例
- 分析
- 代码
A - Tiny Arithmetic Sequence
题目大意
给定序列 A = ( A 1 , A 2 , A 3 ) A=(A_1,A_2,A_3) A=(A1,A2,A3)。能否将 A A A重新排列,使得 A 3 − A 2 = A 2 − A 1 A_3-A_2=A_2-A_1 A3−A2=A2−A1?
1 ≤ A i ≤ 100 1le A_ile 100 1≤Ai≤100
输入格式
A 1 A 2 A 3 A_1~A_2~A_3 A1 A2 A3
输出格式
如果能将
A
A
A重新排列使得
A
3
−
A
2
=
A
2
−
A
1
A_3-A_2=A_2-A_1
A3−A2=A2−A1,输出Yes
;如果不能,输出No
。
样例
A A A | 输出 |
---|---|
( 5 , 1 , 3 ) (5,1,3) (5,1,3) | Yes |
( 1 , 4 , 3 ) (1,4,3) (1,4,3) | No |
( 5 , 5 , 5 ) (5,5,5) (5,5,5) | Yes |
分析
很容易想到,如果
A
3
−
A
2
=
A
2
−
A
1
A_3-A_2=A_2-A_1
A3−A2=A2−A1,则
A
1
≤
A
2
≤
A
3
A_1le A_2le A_3
A1≤A2≤A3或
A
3
≤
A
2
≤
A
1
A_3le A_2le A_1
A3≤A2≤A1必定成立。
因此,我们可以先把
A
A
A按升序排列,再
A
3
−
A
2
=
A
2
−
A
1
A_3-A_2=A_2-A_1
A3−A2=A2−A1是否成立即可。
代码
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int a[3];
scanf("%d%d%d", a, a + 1, a + 2);
sort(a, a + 3);
puts(a[2] - a[1] == a[1] - a[0]? "Yes": "No");
return 0;
}
B - Do you know the second highest mountain?
题目大意
有
N
N
N坐山。第
i
i
i坐山有一个名字
S
i
S_i
Si和高度
T
i
T_i
Ti。
输出第二高的山的名字。
2
≤
N
≤
1000
2le Nle 1000
2≤N≤1000
1
≤
∣
S
i
∣
≤
15
1le |S_i|le 15
1≤∣Si∣≤15
1
≤
T
i
≤
1
0
5
1le T_ile 10^5
1≤Ti≤105
S
i
≠
S
j
(
i
≠
j
)
S_ine S_j~(ine j)
Si=Sj (i=j)
T
i
≠
T
j
(
i
≠
j
)
T_ine T_j~(ine j)
Ti=Tj (i=j)
S
i
S_i
Si由大小写英文字母和数字组成。
输入格式
N
N
N
S
1
T
1
S_1~T_1
S1 T1
S
2
T
2
S_2~T_2
S2 T2
⋮
vdots
⋮
S
N
T
N
S_N~T_N
SN TN
输出格式
输出第二高的山的名字。
样例
样例输入1
3
Everest 8849
K2 8611
Kangchenjunga 8586
样例输出1
K2
第二高的山是K2
。
样例输入2
4
Kita 3193
Aino 3189
Fuji 3776
Okuhotaka 3190
样例输出2
Kita
第二高的山是Kita
。
样例输入3
4
QCFium 2846
chokudai 2992
kyoprofriends 2432
penguinman 2390
样例输出3
QCFium
第二高的山是QCFium
。
分析
这道题其实就是给定求数组 T T T中第二大的元素的 S i S_i Si。我们可以利用优先队列实现求第二大的元素。
代码
#include <iostream>
#include <queue>
#include <string>
using namespace std;
using pis = pair<int, string>;
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n;
cin >> n;
priority_queue<pis, vector<pis>, greater<pis> > q;
while(n--)
{
string s;
int h;
cin >> s >> h;
q.emplace(h, s);
if(q.size() > 2) q.pop();
}
cout << q.top().second << endl;
return 0;
}
C - Secret Number
题目大意
有一个四位的PIN。这个PIN由0
~9
组成,也可能以0
开头。
有一个字符串
S
0
S
1
…
S
9
S_0S_1dots S_9
S0S1…S9,代表每一种数字是否在这个PIN中出现:
- 如果
S
i
=
S_i=~
Si=
o
,这个PIN肯定包含数字 i i i; - 如果
S
i
=
S_i=~
Si=
x
,这个PIN肯定不包含数字 i i i; - 如果
S
i
=
S_i=~
Si=
?
,这个PIN可能包含(也可能不包含)数字 i i i。
有多少个合法的PIN?
S
S
S是一个由o
、x
、?
组成的长度为
10
10
10的字符串。
输入格式
S S S
输出格式
将答案输出为一个整数。
样例
S S S | 答案 |
---|---|
ooo???xxxx | 108 108 108 |
o?oo?oxoxo | 0 0 0 |
xxxxx?xxxo | 15 15 15 |
极端测试点:
S
=
S=~
S= ?????????? ,正确输出:
10000
10000
10000 |
分析
因为可能的PIN数量非常少(最多只有
10000
10000
10000个),所以我们考虑暴力枚举所有可能的PIN,即尝试0000
到9999
之间所有的PIN。对于每个可能的PIN,我们可以在
O
(
∣
S
∣
)
mathcal O(|S|)
O(∣S∣)的时间内判断出它是否合法。
程序的总时间复杂度为
O
(
10000
∣
S
∣
)
mathcal O(10000|S|)
O(10000∣S∣),由于
10000
10000
10000和
∣
S
∣
|S|
∣S∣都是常数,所以也可以看作
O
(
1
)
mathcal O(1)
O(1)。
代码
#include <cstdio>
using namespace std;
char s[15];
inline bool valid(int a, int b, int c, int d)
{
bool used[10] = {false};
used[a] = used[b] = used[c] = used[d] = true;
for(int i=0; i<10; i++)
if(s[i] == 'o')
{
if(!used[i])
return false;
}
else if(s[i] == 'x' && used[i])
return false;
return true;
}
int main()
{
scanf("%s", s);
int ans = 0;
for(int a=0; a<10; a++)
for(int b=0; b<10; b++)
for(int c=0; c<10; c++)
for(int d=0; d<10; d++)
ans += valid(a, b, c, d);
printf("%dn", ans);
return 0;
}
D - Game in Momotetsu World
题目大意
我们有一个
H
×
W
Htimes W
H×W的棋盘,它上面每个小格子都是蓝色或红色的。棋盘上
(
i
,
j
)
(i,j)
(i,j)这个点的颜色取决于
A
i
,
j
A_{i,j}
Ai,j。如果
A
i
,
j
=
A_{i,j}=~
Ai,j= +
,则
(
i
,
j
)
(i,j)
(i,j)为蓝;如果
A
i
,
j
=
A_{i,j}=~
Ai,j= -
,则
(
i
,
j
)
(i,j)
(i,j)为红。
在棋盘上有一颗棋子,它的初始位置在左上角,也就是
(
1
,
1
)
(1,1)
(1,1)。Takahashi和Aoki要用这颗棋子对战。两人一开始都有
0
0
0分,他们要轮流执行如下操作,Takahashi先走:
- 将棋子往右或下移动(不能移出棋盘)。然后,如果移到的点是蓝色的,对应的玩家得一分;否则,玩家扣一分。
当棋子走到
(
H
,
W
)
(H,W)
(H,W)时,游戏结束。此时,如果两人得分相等,则视为平局;否则,得分多的人胜利。
当两人都按最优操作进行游戏时,求最终的游戏结果。
1
≤
H
,
W
≤
2000
1le H,Wle 2000
1≤H,W≤2000
A
i
,
j
A_{i,j}
Ai,j是+
或-
。
输入格式
H
W
H~W
H W
A
1
,
1
A
1
,
2
A
1
,
3
…
A
1
,
W
A_{1,1}A_{1,2}A_{1,3}dots A_{1,W}
A1,1A1,2A1,3…A1,W
A
2
,
1
A
2
,
2
A
2
,
3
…
A
2
,
W
A_{2,1}A_{2,2}A_{2,3}dots A_{2,W}
A2,1A2,2A2,3…A2,W
⋮
vdots
⋮
A
H
,
1
A
H
,
2
A
H
,
3
…
A
H
,
W
A_{H,1}A_{H,2}A_{H,3}dots A_{H,W}
AH,1AH,2AH,3…AH,W
输出格式
如果Takahashi会赢,输出Takahashi
;如果Aoki,输出Aoki
;否则,游戏平局,输出Draw
。
样例
略,请自行前往AtCoder查看。
分析
本题可以使用动态规划的思想。
我们设
d
d
d为
(
Takahashi目前的得分
)
−
(
Aoki目前的得分
)
(text{Takahashi目前的得分})-(text{Aoki目前的得分})
(Takahashi目前的得分)−(Aoki目前的得分),则Takahashi的目标是最大化
d
d
d、Aoki的目标是最小化
d
d
d。我们很容易想到,对于棋子在
(
i
,
j
)
(i,j)
(i,j)时,如果
(
i
+
j
)
(i+j)
(i+j)是奇数,则Aoki走棋,如果它是偶数,则Takahashi走棋。
所以,对于棋盘上的每个点
(
i
,
j
)
(i,j)
(i,j)我们考虑如下
dp
text{dp}
dp:
- 如果 ( i + j ) (i+j) (i+j)是偶数:棋子在 ( i , j ) (i,j) (i,j)时最小的 d d d(这是Aoki走棋)。
- 如果 ( i + j ) (i+j) (i+j)是奇数:棋子在 ( i , j ) (i,j) (i,j)时最大的 d d d(这是Takahashi走棋)。
我们设 a d d ( i , j ) add(i,j) add(i,j)为玩家把棋子走到 ( i , j ) (i,j) (i,j)获得的分数,则有如下 dp text{dp} dp状态:
- 如果 ( i + j ) (i+j) (i+j)是偶数: d p ( i , j ) = min ( d p ( i + 1 , j ) − a d d ( i + 1 , j ) , d p ( i , j + 1 ) − a d d ( i , j + 1 ) ) dp(i,j)=min(dp(i+1,j)-add(i+1,j),dp(i,j+1)-add(i, j+1)) dp(i,j)=min(dp(i+1,j)−add(i+1,j),dp(i,j+1)−add(i,j+1))
- 如果 ( i + j ) (i+j) (i+j)是奇数: d p ( i , j ) = max ( d p ( i + 1 , j ) + a d d ( i + 1 , j ) , d p ( i , j + 1 ) + a d d ( i , j + 1 ) ) dp(i,j)=max(dp(i+1,j)+add(i+1,j),dp(i,j+1)+add(i, j+1)) dp(i,j)=max(dp(i+1,j)+add(i+1,j),dp(i,j+1)+add(i,j+1))
所以,最终我们只需要通过
d
p
(
0
,
0
)
dp(0,0)
dp(0,0)判断结果即可。如果
d
p
(
0
,
0
)
>
0
dp(0,0)>0
dp(0,0)>0,则Takahashi胜;如果
d
p
(
0
,
0
)
<
0
dp(0,0)<0
dp(0,0)<0,Aoki胜;否则,游戏平局。
程序的总时间复杂度为
O
(
N
M
)
mathcal O(NM)
O(NM)。
代码
注意:我这里的dp运用了滚动表的技巧,所以是一维的,当然也可以使用普通的二维dp。
#include <cstdio>
#include <algorithm>
#define maxn 2005
using namespace std;
int dp[maxn], add[maxn][maxn];
int main()
{
int h, w;
scanf("%d%d", &h, &w);
for(int i=0; i<h; i++)
{
char tmp[maxn];
scanf("%s", tmp);
for(int j=0; j<w; j++)
add[i][j] = tmp[j] == '+'? 1: -1;
}
dp[w - 1] = 0;
for(int j=w-2; j>=0; j--)
dp[j] = j + h & 1? dp[j + 1] + add[h - 1][j + 1]: dp[j + 1] - add[h - 1][j + 1];
for(int i=h-2; i>=0; i--)
{
dp[w - 1] = i + w & 1? dp[w - 1] + add[i + 1][w - 1]: dp[w - 1] - add[i + 1][w - 1];
for(int j=w-2; j>=0; j--)
if(i + j & 1)
dp[j] = min(dp[j] - add[i + 1][j], dp[j + 1] - add[i][j + 1]);
else dp[j] = max(dp[j] + add[i + 1][j], dp[j + 1] + add[i][j + 1]);
}
if(dp[0] > 0) puts("Takahashi");
else if(dp[0] < 0) puts("Aoki");
else puts("Draw");
return 0;
}
E - Xor Distances
题目大意
我们有一棵由
N
N
N个顶点组成的加权树。第
i
i
i条边双向连接着顶点
u
i
u_i
ui和
v
i
v_i
vi且有一个权值
w
i
w_i
wi。
对于一对顶点
(
x
,
y
)
(x,y)
(x,y)(
x
≠
y
xne y
x=y),我们如下定义
d
i
s
t
(
x
,
y
)
mathrm{dist}(x,y)
dist(x,y):
- d i s t ( x , y ) = x mathrm{dist}(x,y)=x dist(x,y)=x和 y y y之间的最短路径经过的所有边权值的异或结果。
输出每对点 ( i , j ) (i,j) (i,j)的 d i s t ( i , j ) mathrm{dist}(i,j) dist(i,j)之和,对 ( 1 0 9 + 7 ) (10^9+7) (109+7)取模,即 ∑ i = 1 N − 1 ∑ j = i + 1 N d i s t ( i , j ) m o d ( 1 0 9 + 7 ) sumlimits_{i=1}^{N-1}sumlimits_{j=i+1}^N mathrm{dist}(i,j)bmod(10^9+7) i=1∑N−1j=i+1∑Ndist(i,j)mod(109+7)。
1
≤
N
≤
2
×
1
0
5
1le Nle 2times10^5
1≤N≤2×105
1
≤
u
i
<
v
i
≤
N
1le u_i < v_ile N
1≤ui<vi≤N
0
≤
w
i
<
2
60
0le w_i < 2^{60}
0≤wi<260
输入格式
N
N
N
u
1
v
1
w
1
u_1~v_1~w_1
u1 v1 w1
u
2
v
2
w
2
u_2~v_2~w_2
u2 v2 w2
⋮
vdots
⋮
u
N
−
1
v
N
−
1
w
N
−
1
u_{N-1}~v_{N-1}~w_{N-1}
uN−1 vN−1 wN−1
输出格式
输出每对点 ( i , j ) (i,j) (i,j)的 d i s t ( i , j ) mathrm{dist}(i,j) dist(i,j)之和,对 ( 1 0 9 + 7 ) (10^9+7) (109+7)取模。
样例
略,请自行前往AtCoder查看
分析
首先,我们先看数据范围。
1
≤
N
≤
2
×
1
0
5
1le Nle 2times10^5
1≤N≤2×105
这样一来,最暴力的
O
(
n
3
)
mathcal O(n^3)
O(n3)解法,即枚举所有对点
O
(
n
2
)
mathcal O(n^2)
O(n2)、找最短路
O
(
n
)
mathcal O(n)
O(n)就肯定不行了。
其次,我们尝试优化暴力过程,考虑异或(
⊕
oplus
⊕)的几个特征:
- 0 ⊕ A = A 0oplus A = A 0⊕A=A
- A ⊕ A = 0 Aoplus A = 0 A⊕A=0
- A ⊕ B = B ⊕ A Aoplus B = Boplus A A⊕B=B⊕A
- A ⊕ B ⊕ B = A Aoplus Boplus B = A A⊕B⊕B=A
最后一个特征(异或再异或会抵消掉)实际上就是在告诉我们,
d
i
s
t
(
x
,
y
)
=
d
i
s
t
(
n
,
x
)
⊕
d
i
s
t
(
n
,
y
)
mathrm{dist}(x,y)=mathrm{dist}(n,x)oplusmathrm{dist}(n,y)
dist(x,y)=dist(n,x)⊕dist(n,y),因为
(
n
,
y
)
(n,y)
(n,y)的最短路径中到
n
n
n的多余的一部分直接被最后一次异或抵消掉了。如果不能理解上面的证明,可以用下面的方法证明(设
k
k
k为
x
x
x和
y
y
y的最小共同祖先):
d
i
s
t
(
x
,
y
)
=
d
i
s
t
(
x
,
k
)
⊕
d
i
s
t
(
y
,
k
)
=
d
i
s
t
(
x
,
k
)
⊕
d
i
s
t
(
y
,
k
)
⊕
(
d
i
s
t
(
n
,
k
)
⊕
d
i
s
t
(
n
,
k
)
)
=
(
d
i
s
t
(
x
,
k
)
⊕
d
i
s
t
(
n
,
k
)
)
⊕
(
d
i
s
t
(
y
,
k
)
⊕
d
i
s
t
(
n
,
k
)
)
=
d
i
s
t
(
x
,
n
)
⊕
d
i
s
t
(
y
,
n
)
begin{aligned}mathrm{dist}(x,y)&=mathrm{dist}(x,k)oplusmathrm{dist}(y,k)\&=mathrm{dist}(x,k)oplusmathrm{dist}(y,k)oplus(mathrm{dist}(n,k)oplusmathrm{dist}(n,k))\&=(mathrm{dist}(x,k)oplusmathrm{dist}(n,k))oplus(mathrm{dist}(y,k)oplusmathrm{dist}(n,k))\&=mathrm{dist}(x,n)oplusmathrm{dist}(y,n)end{aligned}
dist(x,y)=dist(x,k)⊕dist(y,k)=dist(x,k)⊕dist(y,k)⊕(dist(n,k)⊕dist(n,k))=(dist(x,k)⊕dist(n,k))⊕(dist(y,k)⊕dist(n,k))=dist(x,n)⊕dist(y,n)
这时,我们可以令
n
=
1
n=1
n=1,并从
n
n
n开始跑一遍搜索,计算出所有的
d
i
s
t
(
n
,
x
)
mathrm{dist}(n,x)
dist(n,x)(时间复杂度
O
(
n
)
mathcal O(n)
O(n)),再对所有的
(
i
,
j
)
(i,j)
(i,j)求出所有的
d
i
s
t
(
n
,
i
)
⊕
d
i
s
t
(
n
,
j
)
mathrm{dist}(n,i)oplusmathrm{dist}(n,j)
dist(n,i)⊕dist(n,j)并求和(时间复杂度
O
(
n
2
)
mathcal O(n^2)
O(n2)),算出结果。这样做的总时间复杂度为
O
(
n
2
)
mathcal O(n^2)
O(n2)。可惜,这样还是过不去。
我们考虑进一步优化。我们发现,对于每个二进制位,在异或的操作下,一个
1
1
1和一个
0
0
0就能组成一个
1
1
1。所以,我们可以统计每一位的
0
0
0和
1
1
1的个数,计算它们的乘积并相加即可。
代码
这里的搜索推荐 BFS text{BFS} BFS,因为这道题中它比 DFS text{DFS} DFS好写且更快,当然 DFS text{DFS} DFS也可以实现。
#include <cstdio>
#include <queue>
#pragma GCC optimize("Ofast")
#define maxn 200005
#define MOD 1000000007LL
using namespace std;
using LL = long long;
vector<pair<int, LL>> G[maxn];
LL d[maxn];
int main()
{
int n;
scanf("%d", &n);
for(int i=1; i<n; i++)
{
int u, v;
LL w;
scanf("%d%d%lld", &u, &v, &w);
G[--u].emplace_back(--v, w);
G[v].emplace_back(u, w);
}
queue<int> q;
q.push(0);
for(int i=1; i<n; i++) d[i] = -1;
while(!q.empty())
{
int v = q.front(); q.pop();
for(auto [u, w]: G[v])
if(d[u] == -1)
q.push(u), d[u] = d[v] ^ w;
}
LL ans = 0LL;
for(int i=0; i<60; i++)
{
int cnt = 0;
for(int j=0; j<n; j++)
if(d[j] >> i & 1LL)
cnt ++;
if((ans += (1LL << i) % MOD * cnt % MOD * (n - cnt) % MOD) > MOD)
ans -= MOD;
}
printf("%lldn", ans);
return 0;
}
最后
以上就是美丽战斗机为你收集整理的Mynavi Programming Contest 2021 (AtCoder Beginner Contest 201) A~E 题解A - Tiny Arithmetic SequenceB - Do you know the second highest mountain?C - Secret NumberD - Game in Momotetsu WorldE - Xor Distances的全部内容,希望文章能够帮你解决Mynavi Programming Contest 2021 (AtCoder Beginner Contest 201) A~E 题解A - Tiny Arithmetic SequenceB - Do you know the second highest mountain?C - Secret NumberD - Game in Momotetsu WorldE - Xor Distances所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复