专栏文章
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
题目
有一个按钮,按下这个按钮时,你会得到一颗糖果,每次得到糖果的时间距离你上次得到糖果的时间大于等于 秒。
高桥决定按这个按钮 次。他将在 秒后按下 次按钮。
他会得到多少颗糖果?
代码
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 几乎相同,只有正文中粗体部分和限制条件不同。
你用双手拿着一个戒指。这个戒指由编号为 的 部分组成,其中 和 部分相邻,而 和 部分也相邻。
最初,您的左手拿着部件 ,右手拿着部件 。在一次操作中,您可以完成以下操作:
- 将其中一只手移动到当前所持部件的相邻部分。但是,只有当另一只手不在目标部件上时才能这样做。
下图显示了初始状态以及可以和不可以进行的操作示例。写在圆环各部分上的数字代表零件编号,标有 L 和 R 的圆圈分别代表你的左手和右手。

你需要按照 的指示依次进行。第 次指令由字符 和整数 表示,意思如下:
- 执行一定数量的操作(可能为零),使您的左手(如果 为
L)或右手(如果 为R)握住 部分。在此,您不得移动 未指定的手。
保证只给出可实现的指令。
求遵循所有指令所需的最小运算总数。
思路
按顺序扫描 指令,同时管理您左右手的当前位置以及到目前为止所需的最少操作次数。对位置的管理非常简单,主要的工作是执行一个程序来响应以下类型的查询:
- 给你一个整数 和 ,每个整数都在 和 之间。从 部分到 部分的循环需要走多少步?不经过部分 ?(保证 和 )。
这个问题可以根据 和 的排序来解决。三个整数有六种可能的排序,因此我们可以考虑每种排序;但是可以通过如下方式将其简化为两种排序,从而简化执行。
首先,我们可以自由交换 和 (从 到 所需的步数等于从 到 所需的步数)。这样,如果有 ,我们就可以将 和 对调,从而始终有 。(这种通过固定排序来减少个案工作的技巧通常很有效)。
剩下的就是 的位置,但基本上有两种情况:,以及其他情况。
对于前者,最佳的下法是 ,需要 步。
对于后者,最佳移动方式是 ,需要 步。
这样,解决问题总共只需 步。
代码
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
题目
有 个玩具,编号从 到 ,有 个盒子,编号从 到 。玩具 的大小为 ,盒子 的大小为 。
高桥想把所有玩具分别存放在不同的盒子里,他决定按以下步骤依次进行:
- 选择一个任意正整数 并购买一个大小为 的盒子。
- 将每个 玩具放入 盒中(现有的 盒加上新买的盒子)。在这里,每个玩具只能放进一个大小不小于该玩具大小的盒子里,任何盒子都不能装两个或两个以上的玩具。
他想通过在步骤 中购买一个足够大的盒子来执行步骤 ,但是大盒子的价格更高,所以他想购买尽可能小的盒子。
请判断是否存在一个 的值,使他可以执行步骤 ,如果存在,求这样的 的最小值。
思路
让我们首先考虑一下,当我们确定新购买的箱子的大小为 时,如何确定步骤 是否可行。
总之,可以使用下面的命题:
将 按升序排序,得到 。将 插入 ,并按升序排序,得到 。那么当且仅当 代表所有的 时,步骤 才是可行的。
证明:
- 充分性显而易见,因此我们将证明必要性:“如果第 步可行,则所有 均为 。”
- 将玩具和盒子重新编号,这样 对应的玩具称为玩具 , 对应的盒子称为盒子 。当第 步可行时,存在一个 的排列 ,使得“所有 都是 ”。
- 假设存在 与 。那么我们有 ,因此有 和 ;那么在交换 和 之后,仍然成立。当 与 同时存在时,重复这一操作,就可以得到 ,同时保持。当 存在时,表示所有 的 ,这正是我们想要的结果。
因此,根据这个条件,我们可以使用二进制搜索找到满足条件的最小值 。如果对每个决策的序列 和 进行排序,总共需要花费 ,这可以在时间限制内完成;也可以调整优化为 。
我们也可以不用二进制搜索,而用下面的贪心算法来解决这个问题。(有效性来自上面对固定 的讨论。)复杂度为 ,其中排序是瓶颈。
- 假设玩具 和盒子 分别是最大的剩余玩具和盒子。
- 如果 :将玩具 放入盒子 是最优选择。从玩具集合中删除玩具 ,从盒子集合中删除盒子 ;返回第 步。
- 如果 :你无法将玩具 放入任何一个剩余的盒子中,因此你需要购买一个大小至少为 的新盒子。购买一个大小超过 的盒子是没有用的,因此设置 来应用上述标准。如果符合,则答案为 ;否则为 。
通过观察这个贪心算法的行为,我们可以得出一个更简单的算法,如下所示。复杂度仍为 。
- 将 和 按升序排序。
- 如果存在 与 :答案为 。
- 否则:答案为 ,其中 是 与 的最大值(或 ,如果什么都不适用)。
代码
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 条评论,欢迎与作者交流。
正在加载评论...