ABC239/Denso2022 C~E
C - Knight Fork
题目大意
在二维平面上是否有一个整数坐标点到 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)和 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)的欧几里得距离都是 5 \sqrt5 5?
输入格式
x 1 y 1 x 2 y 2 x_1~y_1~x_2~y_2 x1 y1 x2 y2
输出格式
如果存在符合条件的点,输出Yes
;否则,输出No
。
样例
x 1 x_1 x1 | y 1 y_1 y1 | x 2 x_2 x2 | y 2 y_2 y2 | 输出 |
---|---|---|---|---|
0 0 0 | 0 0 0 | 3 3 3 | 3 3 3 | Yes |
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | No |
1000000000 1000000000 1000000000 | 1000000000 1000000000 1000000000 | 999999999 999999999 999999999 | 999999999 999999999 999999999 | Yes |
分析
我们首先要知道,什么是“距离为
5
\sqrt5
5”。设
(
a
−
c
)
2
+
(
b
−
d
)
2
=
5
\sqrt{(a-c)^2+(b-d)^2}=\sqrt5
(a−c)2+(b−d)2=5(
a
,
b
,
c
,
d
a,b,c,d
a,b,c,d均为整数),则有:
(
a
−
c
)
2
+
(
b
−
d
)
2
=
5
{
a
−
c
,
b
−
d
}
=
{
1
,
2
}
(a-c)^2+(b-d)^2=5\\ \{a-c,b-d\}=\{1,2\}
(a−c)2+(b−d)2=5{a−c,b−d}={1,2}
所以,对于
(
0
,
0
)
(0,0)
(0,0)这个点,有如下距离为
5
\sqrt5
5的点(其他点都类似):
所以,我们对找到
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1)所有的距离为
5
\sqrt5
5的点,并对计算与
(
x
2
,
y
2
)
(x_2,y_2)
(x2,y2)的距离即可。
代码
#include <cstdio>
using namespace std;
using LL = long long;
const int d[8] = {-1, 1, 2, 2, 1, -1, -2, -2};
inline LL sqr2(const LL& x, const LL& y)
{
return x * x + y * y;
}
int main()
{
LL x1, y1, x2, y2;
scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
x1 -= x2, y1 -= y2;
for(int i=0; i<8; i++)
if(sqr2(x1 + d[i], y1 + d[(i + 2) & 7]) == 5)
{
puts("Yes");
return 0;
}
puts("No");
return 0;
}
D - Prime Sum Game
题目大意
水题警告
Takahashi和Aoki在玩一个游戏。游戏过程如下:
- Takahashi在中选择一个整数 A ≤ N ≤ B A\le N\le B A≤N≤B。
- Aoki中选择一个整数 C ≤ M ≤ D C\le M\le D C≤M≤D。
- 如果 N + M N+M N+M是质数,Aoki获胜。否则,Takahashi获胜。
当两人都按最优策略游戏时,谁会赢得比赛?
1
≤
A
≤
B
≤
100
1\le A\le B\le 100
1≤A≤B≤100
1
≤
C
≤
D
≤
100
1\le C\le D\le 100
1≤C≤D≤100
输入格式
A B C D A~B~C~D A B C D
输出格式
输出胜者的名字,即Takahashi
或Aoki
。
样例
A A A | B B B | C C C | D D D | 输出 |
---|---|---|---|---|
2 2 2 | 3 3 3 | 3 3 3 | 4 4 4 | Aoki |
1 1 1 | 100 100 100 | 50 50 50 | 60 60 60 | Takahashi |
3 3 3 | 14 14 14 | 1 1 1 | 5 5 5 | Aoki |
分析
要解决这道题,首先要知道什么是“最优策略”。
显然,当Takahashi选择的
N
N
N加上任意的
M
M
M都不是质数时,Takahashi胜利;
否则,当任意的
N
N
N加上某一个
M
M
M都得到质数时,Aoki胜利。
因为数据范围较小,我们可以暴力枚举所有
N
N
N和
M
M
M,质数判断耗时可以忽略不计。因此,总时间复杂度约为
O
(
B
D
)
\mathcal O(BD)
O(BD)。
代码
P.S. 不可思议,运行时间居然是 4 m s 4\mathrm{ms} 4ms…(本来以为至少也有 30 m s 30\mathrm{ms} 30ms的…)
#include <cstdio>
using namespace std;
inline bool isprime(int x)
{
for(int t=__builtin_sqrt(x), i=2; i<=t; i++)
if(x % i == 0)
return false;
return true;
}
int main()
{
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
for(int i=a; i<=b; i++)
{
int j = c;
for(; j<=d; j++)
if(isprime(i + j))
break;
if(j > d) { puts("Takahashi"); return 0; }
}
puts("Aoki");
return 0;
}
E - Subtree K-th Max
题目大意
有一个由
N
N
N个节点(节点
1
1
1,…,节点
N
N
N)组成的树(根节点为节点
1
1
1)。
第
i
i
i条边连接节点
A
i
A_i
Ai和
B
i
B_i
Bi。节点
v
v
v有一个数值
X
v
X_v
Xv。
给定
Q
Q
Q个询问,第
i
i
i个询问由
(
V
i
,
K
i
)
(V_i,K_i)
(Vi,Ki)组成:
- 在以节点 V i V_i Vi为根的子树当中,求所有节点的数值的第 K K K大值(不去重)。
2
≤
N
,
Q
≤
1
0
5
2\le N,Q\le 10^5
2≤N,Q≤105
0
≤
X
i
≤
1
0
9
0\le X_i\le 10^9
0≤Xi≤109
1
≤
A
i
,
B
i
,
V
i
≤
N
1\le A_i,B_i,V_i\le N
1≤Ai,Bi,Vi≤N
1
≤
K
i
≤
20
1\le K_i\le 20
1≤Ki≤20
输入格式
N
Q
N~Q
N Q
X
1
…
X
N
X_1~\dots~X_N
X1 … XN
A
1
B
1
A_1~B_1
A1 B1
⋮
\vdots
⋮
A
N
−
1
B
N
−
1
A_{N-1}~B_{N-1}
AN−1 BN−1
V
1
K
1
V_1~K_1
V1 K1
⋮
\vdots
⋮
V
Q
K
Q
V_Q~K_Q
VQ KQ
输出格式
输出 Q Q Q行。第 i i i行应包含对第 i i i个询问的回答。
样例
略,请自行前往AtCoder查看
分析
我们首先发现题面中,
1
≤
K
≤
20
1\le K\le 20
1≤K≤20。于是我们对每个节点分别存储以它为根的子树中前
20
20
20的数值。
于是,我们按照拓扑序(或直接
DFS
\text{DFS}
DFS),执行如下操作:
- 对于叶子节点,我们只存储一个当前的数值。
- 对于其他的节点,先排序当前节点数值和所有孩子的前 20 20 20,排序后取前 20 20 20即可。
排序建议用priority_queue
,时间复杂度
O
(
N
+
Q
)
\mathcal O(N+Q)
O(N+Q)或
O
(
N
log
N
+
Q
)
\mathcal O(N\log N+Q)
O(NlogN+Q)(直接排序)。
代码
示例代码实现方式为DFS + priority_queue
,用时
190
m
s
190\mathrm{ms}
190ms
#include <cstdio>
#include <queue>
#define maxn 100005
using namespace std;
int x[maxn];
vector<int> G[maxn], dp[maxn];
void dfs(int v, int par)
{
priority_queue<int, vector<int>, greater<int>> q;
q.push(x[v]);
for(int u: G[v])
if(u != par)
{
dfs(u, v);
for(int val: dp[u])
{
q.push(val);
if(q.size() > 20) q.pop();
}
}
while(!q.empty())
{
dp[v].push_back(q.top());
q.pop();
}
}
int main()
{
int n, q;
scanf("%d%d", &n, &q);
for(int i=0; i<n; i++)
scanf("%d", x + i);
for(int i=1; i<n; i++)
{
int a, b;
scanf("%d%d", &a, &b);
G[--a].push_back(--b);
G[b].push_back(a);
}
dfs(0, -1);
while(q--)
{
int v, k;
scanf("%d%d", &v, &k);
const auto& d = dp[--v];
printf("%d\n", d[d.size() - k]);
}
return 0;
}