当前位置:   article > 正文

AtCoder Beginner Contest 204 A~E 题解_[abc204d] cooking

[abc204d] cooking

A - Rock-paper-scissors

题目大意

三个人玩石头剪刀布平局,其中两个出的分别是 x , y x,y x,y,求另一个人出的。

0 ≤ x , y ≤ 2 0\le x,y\le 2 0x,y2 0 , 1 , 2 0,1,2 0,1,2分别表示石头,剪刀,布)

输入格式

x , y x,y x,y

输出格式

用整数格式输出答案。

样例

x x x y y y输出
0 0 0 1 1 1 2 2 2
0 0 0 0 0 0 0 0 0

分析

石头剪刀布这个游戏三人平局只有两种情况(设 z z z为第三个人出的):

  • x = y = z x=y=z x=y=z
  • x ≠ y ≠ z x\ne y\ne z x=y=z

所以,我们得出如下递推式:
z = { x ( x = y ) 3 − x − y ( x ≠ y ) z={x(x=y)3xy(xy)

z={x3xy(x=y)(x=y)

代码

#include <cstdio>
using namespace std;

int main()
{
	int x, y;
	scanf("%d%d", &x, &y);
	printf("%d\n", x == y? x: 3 - x - y);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

B - Nuts

题目大意

N N N棵树,第 i i i棵树上有 A i A_i Ai颗果实。
一个人会从第 i i i棵树摘下 max ⁡ ( 0 , A i − 10 ) \max(0,A_i-10) max(0,Ai10)颗果实。他一共会得到多少果实?

1 ≤ N , A i ≤ 1000 1\le N,A_i\le 1000 1N,Ai1000

输入格式

N N N
A 1   …   A N A_1~\dots~A_N A1  AN

输出格式

输出答案。

样例

样例输入1

3
6 17 28
  • 1
  • 2

样例输出1

25
  • 1

他会从三棵树上分别摘下 0 , 7 , 18 0,7,18 0,7,18颗果实,总共 25 25 25颗。

样例输入2

4
8 9 10 11
  • 1
  • 2

样例输出2

1
  • 1

他只会从最后一棵树上得到一颗果实。

分析

我们直接按题意模拟即可。

代码

#include <cstdio>
using namespace std;

int main()
{
	int n, ans = 0;
	scanf("%d", &n);
	while(n--)
	{
		int a;
		scanf("%d", &a);
		if(a > 10) ans += a - 10;
	}
	printf("%d\n", ans);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

C - Tour

题目大意

一个国家有编号为 1 1 1 N N N N N N座城市和编号为 1 1 1 M M M M M M条路。
i i i条路从城市 A i A_i Ai B i B_i Bi,且不能用它从城市 B i B_i Bi A i A_i Ai
一个人想从起点城市开始旅行并走过若干条路(可以不走,即只游玩一个城市)并到达终点城市。
有多少种合法的起点和终点城市?如果 X ≠ Y X\ne Y X=Y,则 X → Y X\to Y XY Y → X Y\to X YX算作两种不同的方案。

2 ≤ N ≤ 2000 2\le N\le 2000 2N2000
0 ≤ M ≤ min ⁡ ( 2000 , N ( N − 1 ) ) 0\le M\le \min(2000,N(N-1)) 0Mmin(2000,N(N1))
1 ≤ A i , B i ≤ N 1\le A_i,B_i\le N 1Ai,BiN
A i ≠ B i A_i\ne B_i Ai=Bi
( A i , B i ) (A_i,B_i) (Ai,Bi)互不相同。

输入格式

N   M N~M N M
A 1   B 1 A_1~B_1 A1 B1
⋮ \vdots
A M   B M A_M~B_M AM BM

输出格式

输出答案。

样例

样例输入1

3 3
1 2
2 3
3 2
  • 1
  • 2
  • 3
  • 4

样例输出1

7
  • 1

有七种可行的旅游方案: 1 → 1 1\to1 11 1 → 2 1\to2 12 1 → 3 1\to3 13 2 → 2 2\to2 22 2 → 3 2\to3 23 3 → 2 3\to2 32 3 → 3 3\to3 33

样例输入2

3 0
  • 1

样例输出2

3
  • 1

有三种可行的旅游方案: 1 → 1 1\to1 11 2 → 2 2\to2 22 3 → 3 3\to3 33

分析

我们可以把这个国家看成一个简单有向无权图,并把每个节点作为起点跑一遍 DFS \text{DFS} DFS,计算总共能到达的结点数即可。
总时间复杂度为 O ( n 2 ) \mathcal O(n^2) O(n2)

代码

注意:每次 DFS \text{DFS} DFS之前一定要将 v i s \mathrm{vis} vis数组清零!

#include <cstdio>
#include <vector>
#define maxn 2005
using namespace std;

vector<int> G[maxn];
bool vis[maxn];

int ans;

void dfs(int v)
{
	if(vis[v]) return;
	vis[v] = true, ans ++;
	for(int u: G[v])
		dfs(u);
}

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	while(m--)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		G[--x].push_back(--y);
	}
	ans = 0;
	for(int i=0; i<n; i++)
	{
		for(int j=0; j<n; j++)
			vis[j] = false;
		dfs(i);
	}
	printf("%d\n", ans);
	return 0;
}
  • 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

D - Cooking

题目大意

两个人要洗 N N N个碗,其中任意一个人洗第 i i i个碗需要 T i T_i Ti分钟。一个人不能同时洗多个碗。
两个人一起洗碗,洗完所有碗至少需要多少分钟?

1 ≤ N ≤ 100 1\le N\le 100 1N100
1 ≤ T i ≤ 1 0 3 1\le T_i\le 10^3 1Ti103

输入格式

N N N
T 1   T 2   …   T N T_1~T_2~\dots~T_N T1 T2  TN

输出格式

输出答案。

样例

样例输入1

5
8 3 7 2 5
  • 1
  • 2

样例输出1

13
  • 1

我们可以让两个人分别洗如下的碗:

  • 第一个人洗编号为 5 , 1 5,1 5,1的碗。总时间为 T 5 + T 1 = 13 T_5+T_1=13 T5+T1=13分钟。
  • 第二个人洗编号为 2 , 4 , 3 2,4,3 2,4,3的碗。总时间为 T 2 + T 4 + T 3 = 10 T_2+T_4+T_3=10 T2+T4+T3=10分钟。

总耗时为 max ⁡ ( 13 , 10 ) = 13 \max(13,10)=13 max(13,10)=13分钟。

样例输入2

2
1000 1
  • 1
  • 2

样例输出2

1000
  • 1

样例输入3

9
3 14 15 9 26 5 35 89 79
  • 1
  • 2

样例输出3

138
  • 1

分析

这是一道经典01背包题。
题目可以直接描述为:给定序列 T T T,将其分成两个子序列 A A A B B B(不要求连续),求最小的 min ⁡ ( ∑ A , ∑ B ) \min(\sum A,\sum B) min(A,B)
这时,我们发现要使 min ⁡ ( ∑ A , ∑ B ) \min(\sum A,\sum B) min(A,B)最小,由于 ∑ A + ∑ B = ∑ T \sum A+\sum B=\sum T A+B=T,所以 ∣ ∑ A − ∑ B ∣ |\sum A-\sum B| AB必须也达到最小。
我们可以将 ∑ T \sum T T分成两半,其中一半为 ⌊ ∑ T 2 ⌋ \lfloor\frac{\sum T}2\rfloor 2T。这时,我们可以用dp背包解决此题:从 T T T中选出一个子序列 A A A,使得 ∑ A ≤ ⌊ ∑ T 2 ⌋ \sum A\le\lfloor\frac{\sum T}2\rfloor A2T,这样答案就为 ∑ T − ∑ A \sum T-\sum A TA

代码

#include <cstdio>
#define maxn 105
#define maxv 100005
using namespace std;

int dp[maxv], w[maxn];

inline void setmax(int& x, int y)
{
	if(y > x) x = y;
}

int main()
{
	int n, v = 0;
	scanf("%d", &n);
	for(int i=0; i<n; i++)
	{
		scanf("%d", w + i);
		v += w[i];
	}
	int t = v;
	v >>= 1;
	for(int i=0; i<n; i++)
		for(int j=v; j>=w[i]; j--)
			setmax(dp[j], dp[j - w[i]] + w[i]);
	printf("%d\n", t - dp[v]);
	return 0;
}
  • 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

E - Rush Hour 2

题目大意

一个国家有 N N N座城市和 M M M条路。城市的编号是 1 1 1 N N N,路的编号则为 1 1 1 M M M。第 i i i条路双向连接着城市 A i A_i Ai B i B_i Bi
在这个国家中,初始时间为 0 0 0。如果你在时间点 t t t通过公路 i i i,所需时间为 C i + ⌊ D i t + 1 ⌋ C_i+\lfloor\frac {D_i} {t+1}\rfloor Ci+t+1Di
一个人想从城市 1 1 1到达城市 N N N。他在每个城市可以停留任意自然数的时间。
求这个人最早到达城市 N N N的时间。如果无法到达城市 N N N,输出-1

2 ≤ N ≤ 1 0 5 2\le N\le 10^5 2N105
2 ≤ M ≤ 1 0 5 2\le M\le 10^5 2M105
1 ≤ A i , B i ≤ N 1\le A_i,B_i\le N 1Ai,BiN
0 ≤ C i , D i ≤ 1 0 9 0\le C_i,D_i\le 10^9 0Ci,Di109

输入格式

N   M N~M N M
A 1   B 1   C 1   D 1 A_1~B_1~C_1~D_1 A1 B1 C1 D1
⋮ \vdots
A M   B M   C M   D M A_M~B_M~C_M~D_M AM BM CM DM

输出格式

输出答案。

样例

样例输入1

2 1
1 2 2 3
  • 1
  • 2

样例输出1

4
  • 1

我们可以先在城市 1 1 1停留至时间 1 1 1。然后,我们出发,最终到达时间 1 + 2 + ⌊ 3 1 + 1 ⌋ = 4 1+2+\lfloor\frac 3 {1+1}\rfloor=4 1+2+1+13=4

样例输入2

2 3
1 2 2 3
1 2 2 1
1 1 1 1
  • 1
  • 2
  • 3
  • 4

样例输出2

3
  • 1

两个城市之间可能有多条路,一个城市也可能有到自己的路。

样例输入3

4 2
1 2 3 4
3 4 5 6
  • 1
  • 2
  • 3

样例输出3

-1
  • 1

城市 1 1 1到城市 N N N可能没有路径。

分析

我们可以把输入当成一幅无向图。其实,从一个城市到它自己的路根本没有用,所以我们直接忽略不计。
如果目前时间为 T T T且我们要从城市 A i A_i Ai B i B_i Bi,我们可以证明,最好的整数出发时间应该是 ⌊ D ⌉ − 1 \lfloor\sqrt D\rceil-1 D 1 ⌊ x ⌉ \lfloor x\rceil x表示 x x x四舍五入)。
如果 ⌊ D ⌉ ≤ T \lfloor\sqrt D\rceil\le T D T,我们应该等到时间 ⌊ D ⌉ − 1 \lfloor\sqrt D\rceil-1 D 1再出发;否则,我们直接出发。
这时,我们可以使用Dijkstra最短路算法(使用优先队列优化),这样总时间复杂度就为 O ( M log ⁡ N ) \mathcal O(M\log N) O(MlogN)

代码

#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <tuple>
#define maxn 100005
#define INF 9223372036854775807LL
using namespace std;

using Road = tuple<int, int, int>;
using LL = long long;
using pli = pair<LL, int>;

vector<Road> G[maxn];
LL dist[maxn];

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	while(m--)
	{
		int a, b, c, d;
		scanf("%d%d%d%d", &a, &b, &c, &d);
		if(--a == --b) continue;
		G[a].emplace_back(b, c, d);
		G[b].emplace_back(a, c, d);
	}
	dist[0] = 0LL;
	for(int i=1; i<n; i++) dist[i] = INF;
	priority_queue<pli, vector<pli>, greater<pli>> q;
	q.emplace(0LL, 0);
	while(!q.empty())
	{
		auto [t, u] = q.top(); q.pop();
		if(dist[u] != t) continue;
		for(auto [v, c, d]: G[u])
		{
			LL t2 = sqrt((long double) d) - 0.5;
			if(t2 < t) t2 = t;
			t2 += LL(c) + LL(d) / (t2 + 1LL);
			if(t2 < dist[v])
				q.emplace(dist[v] = t2, v);
		}
	}
	if(dist[n - 1] == INF) puts("-1");
	else printf("%lld\n", dist[n - 1]);
	return 0;
}
  • 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
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/74438
推荐阅读
相关标签
  

闽ICP备14008679号