专栏文章

AtCoder Beginner Contest 376 A~C

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqwrml0
此快照首次捕获于
2025/12/04 12:00
3 个月前
此快照最后确认于
2025/12/04 12:00
3 个月前
查看原文

A - Candy Button


题目

有一个按钮,按下这个按钮时,你会得到一颗糖果,每次得到糖果的时间距离你上次得到糖果的时间大于等于 CC 秒。
高桥决定按这个按钮 NN 次。他将在 TiT_i 秒后按下 ii 次按钮。
他会得到多少颗糖果?

代码

CPP
#include <bits/stdc++.h>

using namespace std;

int n, c, a, cnt = 1, x;

int main()
{
	scanf("%d %d\n%d", &n, &c, &x);
	for (int i = 1; i < n; i ++ )
	{
		scanf("%d", &a);
		if (a - x >= c)
		{
			cnt ++;
			x = a;
		}
	}
	cout << cnt << '\n';
	return 0;
}

B - Hands on Ring (Easy)


题目

注:本问题的设置与问题 F 几乎相同,只有正文中粗体部分和限制条件不同。
你用双手拿着一个戒指。这个戒指由编号为 1,2,,N1,2, \ldots ,NN(N3)N(N \ge 3) 部分组成,其中 iii+1(1iN1)i+1(1 \le i \le N-1) 部分相邻,而 11NN 部分也相邻。
最初,您的左手拿着部件 11,右手拿着部件 22。在一次操作中,您可以完成以下操作:
  • 将其中一只手移动到当前所持部件的相邻部分。但是,只有当另一只手不在目标部件上时才能这样做。
下图显示了初始状态以及可以和不可以进行的操作示例。写在圆环各部分上的数字代表零件编号,标有 L 和 R 的圆圈分别代表你的左手和右手。
你需要按照 QQ 的指示依次进行。第 i(1iQ)i(1 \le i \le Q) 次指令由字符 HiH_i 和整数 TiT_i 表示,意思如下:
  • 执行一定数量的操作(可能为零),使您的左手(如果 HiH_iL)或右手(如果 HiH_iR)握住 TiT_i 部分。在此,您不得移动 HiH_i 未指定的手。
保证只给出可实现的指令。
求遵循所有指令所需的最小运算总数。

思路

按顺序扫描 QQ 指令,同时管理您左右手的当前位置以及到目前为止所需的最少操作次数。对位置的管理非常简单,主要的工作是执行一个程序来响应以下类型的查询:
  • 给你一个整数 from,tofrom,tongng,每个整数都在 11NN 之间。从 fromfrom 部分到 toto 部分的循环需要走多少步?不经过部分 ngng?(保证 fromngfrom \ne ngtongto \ne ng)。
这个问题可以根据 from,tofrom,tongng 的排序来解决。三个整数有六种可能的排序,因此我们可以考虑每种排序;但是可以通过如下方式将其简化为两种排序,从而简化执行。
首先,我们可以自由交换 fromfromtoto(从 fromfromtoto 所需的步数等于从 totofromfrom 所需的步数)。这样,如果有 from>tofrom>to,我们就可以将 fromfromtoto 对调,从而始终有 fromtofrom \le to。(这种通过固定排序来减少个案工作的技巧通常很有效)。
剩下的就是 ngng 的位置,但基本上有两种情况:from<ng<tofrom<ng<to,以及其他情况。
对于前者,最佳的下法是 from(from1)1N(to+1)tofrom \to (from-1) \to \cdots \to 1 \to N \to \cdots \to(to+1) \to to,需要 (from1)+1+(Nto)=N+fromto(from-1)+1+(N-to)=N+from-to 步。
对于后者,最佳移动方式是 from(from+1)(to1)tofrom \to (from+1) \to \cdots \to (to-1) \to to,需要 tofromto-from 步。
这样,解决问题总共只需 O(N)O(N) 步。

代码

CPP
#include <bits/stdc++.h>

using namespace std;

int n, q, l = 1, r = 2, ans, t;
char h;

int num_move(int n, int from, int to, int ng)
{
	if (from > to)
		swap(from, to);
	if (from < ng and ng < to)
		return n + from - to;
	else
		return to - from;
}

int main()
{
	scanf("%d %d", &n, &q);
	for (int i = 0; i < q; i ++ )
	{
		cin >> h;
		scanf("%d", &t);
		if (h == 'L')
		{
			ans += num_move(n, l, t, r);
			l = t;
		}
		else
		{
			ans += num_move(n, r, t, l);
			r = t;
		}
	}
	cout << ans << '\n';
	return 0;
}

C - Prepare Another Box


题目

NN 个玩具,编号从 11NN,有 N1N-1 个盒子,编号从 11N1N-1。玩具 i(1iN)i(1 \le i \le N) 的大小为 AiA_i,盒子 i(1iN1)i(1 \le i \le N-1) 的大小为 BiB_i
高桥想把所有玩具分别存放在不同的盒子里,他决定按以下步骤依次进行:
  1. 选择一个任意正整数 xx 并购买一个大小为 xx 的盒子。
  2. 将每个 NN 玩具放入 NN 盒中(现有的 N1N-1 盒加上新买的盒子)。在这里,每个玩具只能放进一个大小不小于该玩具大小的盒子里,任何盒子都不能装两个或两个以上的玩具。
他想通过在步骤 11 中购买一个足够大的盒子来执行步骤 22,但是大盒子的价格更高,所以他想购买尽可能小的盒子。
请判断是否存在一个 xx 的值,使他可以执行步骤 22,如果存在,求这样的 xx 的最小值。

思路

让我们首先考虑一下,当我们确定新购买的箱子的大小为 xx 时,如何确定步骤 22 是否可行。
总之,可以使用下面的命题:
AA 按升序排序,得到 a=(a1,a2,,aN)a=(a_1,a_2, \ldots ,a_N)。将 xx 插入 BB,并按升序排序,得到 b=(b1,b2,,bN)b=(b_1,b_2, \ldots ,b_N)。那么当且仅当 aibia_i \le b_i 代表所有的 i(1iN)i(1 \le i \le N) 时,步骤 22 才是可行的。
证明:
  • 充分性显而易见,因此我们将证明必要性:“如果第 22 步可行,则所有 i(1iN)i(1 \le i \le N) 均为 aibia_i \le b_i。”
  • 将玩具和盒子重新编号,这样 aia_i 对应的玩具称为玩具 iibib_i 对应的盒子称为盒子 ii。当第 22 步可行时,存在一个 (1,2,N)(1,2 \ldots ,N) 的排列 p=(p1,p2,,pN)p=(p_1,p_2, \ldots ,p_N),使得“所有 i(1iN)i(1 \le i \le N) 都是 aibpia_i \le b_{p_i}”。
  • 假设存在 i(1i<N)i(1 \le i<N)pi>pi+1p_i>p_{i+1}。那么我们有 aiai+1bpi+1bpia_i \le a_{i+1} \le b_{p_{i+1}} \le b_{p_i},因此有 aibpi+1a_i \le b_{p_{i+1}}ai+1bpia_{i+1} \le b_{p_i};那么在交换 pip_ipi+1p_{i+1} 之后,仍然成立。当 i(1i<N)i(1 \le i<N)pi>pi+1p_i>p_{i+1} 同时存在时,重复这一操作,就可以得到 p=(1,2,,N)p=(1,2, \ldots ,N),同时保持。当 p=(1,2,,N)p=(1,2, \ldots ,N) 存在时,表示所有 i(1iN)i(1 \le i \le N)aibia_i \le b_i,这正是我们想要的结果。
因此,根据这个条件,我们可以使用二进制搜索找到满足条件的最小值 xx。如果对每个决策的序列 aabb 进行排序,总共需要花费 O(Nlog(maxAi)logN)O(N \log (\max A_i)\log N),这可以在时间限制内完成;也可以调整优化为 O(Nlog(maxAi))O(N \log (\max A_i))
我们也可以不用二进制搜索,而用下面的贪心算法来解决这个问题。(有效性来自上面对固定 xx 的讨论。)复杂度为 O(NlogN)O(N \log N),其中排序是瓶颈。
  1. 假设玩具 ii 和盒子 jj 分别是最大的剩余玩具和盒子。
  2. 如果 AiBjA_i \le B_j:将玩具 ii 放入盒子 jj 是最优选择。从玩具集合中删除玩具 ii,从盒子集合中删除盒子 jj;返回第 11 步。
  3. 如果 Ai>BjA_i>B_j:你无法将玩具 ii 放入任何一个剩余的盒子中,因此你需要购买一个大小至少为 AiA_i 的新盒子。购买一个大小超过 AiA_i 的盒子是没有用的,因此设置 x=Aix=A_i 来应用上述标准。如果符合,则答案为 AiA_i;否则为 1-1
通过观察这个贪心算法的行为,我们可以得出一个更简单的算法,如下所示。复杂度仍为 O(NlogN)O(N \log N)
  1. AABB 按升序排序。
  2. 如果存在 i(1iN1)i(1 \le i \le N-1)Ai>BiA_i>B_i:答案为 1-1
  3. 否则:答案为 Ai+1A_{i'+1},其中 ii'i(1iN1)i(1 \le i \le N-1)Ai+1>BiA_{i+1}>B_i 的最大值(或 00,如果什么都不适用)。

代码

CPP
#include <bits/stdc++.h>

using namespace std;

int n;

int main()
{
	scanf("%d", &n);
	vector<int> a(n), b(n - 1);
	for (int &i : a)
		scanf("%d", &i);
	for (int &i : b)
		scanf("%d", &i);
	sort(a.begin(), a.end());
	sort(b.begin(), b.end());
	for (int i = 0; i < n - 1; i ++ )
	{
		if (a[i] > b[i])
		{
			puts("-1");
			return 0;
		}
	}
	for (int i = n - 2; i >= 0; i -- )
	{
		if (a[i + 1] > b[i])
		{
			cout << a[i + 1] << '\n';
			return 0;
		}
	}
	cout << a[0] << '\n';
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...