Denso Create Programming Contest 2022 (AtCoder Beginner Contest 239) C~E 题解

46 篇文章 7 订阅
43 篇文章 6 订阅

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 3Yes
0 0 0 1 1 1 2 2 2 3 3 3No
1000000000 1000000000 1000000000 1000000000 1000000000 1000000000 999999999 999999999 999999999 999999999 999999999 999999999Yes

分析

我们首先要知道,什么是“距离为 5 \sqrt5 5 ”。设 ( a − c ) 2 + ( b − d ) 2 = 5 \sqrt{(a-c)^2+(b-d)^2}=\sqrt5 (ac)2+(bd)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\} (ac)2+(bd)2=5{ac,bd}={1,2}
所以,对于 ( 0 , 0 ) (0,0) (0,0)这个点,有如下距离为 5 \sqrt5 5 的点(其他点都类似):
距离sqrt5解释图
所以,我们对找到 ( 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在玩一个游戏。游戏过程如下:

  1. Takahashi在中选择一个整数 A ≤ N ≤ B A\le N\le B ANB
  2. Aoki中选择一个整数 C ≤ M ≤ D C\le M\le D CMD
  3. 如果 N + M N+M N+M是质数,Aoki获胜。否则,Takahashi获胜。

当两人都按最优策略游戏时,谁会赢得比赛?

1 ≤ A ≤ B ≤ 100 1\le A\le B\le 100 1AB100
1 ≤ C ≤ D ≤ 100 1\le C\le D\le 100 1CD100

输入格式

A   B   C   D A~B~C~D A B C D

输出格式

输出胜者的名字,即TakahashiAoki

样例

A A A B B B C C C D D D输出
2 2 2 3 3 3 3 3 3 4 4 4Aoki
1 1 1 100 100 100 50 50 50 60 60 60Takahashi
3 3 3 14 14 14 1 1 1 5 5 5Aoki

分析

要解决这道题,首先要知道什么是“最优策略”。
显然,当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 2N,Q105
0 ≤ X i ≤ 1 0 9 0\le X_i\le 10^9 0Xi109
1 ≤ A i , B i , V i ≤ N 1\le A_i,B_i,V_i\le N 1Ai,Bi,ViN
1 ≤ K i ≤ 20 1\le K_i\le 20 1Ki20

输入格式

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} AN1 BN1
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 1K20。于是我们对每个节点分别存储以它为根的子树中前 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;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值