1 条题解
-
0
B. Robot Program 详细题解
问题理解
我们有一个机器人在数轴上运动,初始位置为 (),有一条长度为 的指令序列 (由 和 组成)。
机器人按顺序执行指令(每秒一条),但有一个关键规则: 每当机器人到达位置 时,指令计数器立即重置,即重新从 的第一条指令开始执行。
如果机器人执行完所有 条指令后,当前位置不是 ,它就停止运行。
我们需要计算在接下来的 秒内,机器人进入 点的次数。
注意:“进入”意味着到达 点的那一瞬间算一次,包括初始时刻吗?
根据题意,机器人从 ()开始,所以初始不在 。第一次进入 是在某次移动之后。
核心观察
这个问题可以分解成几个阶段:
阶段 1:第一次到达 点
从初始位置 出发,按顺序执行指令,直到第一次到达 点。
设经过 秒(即执行了 条指令)后,机器人第一次到达 。
如果在整个第一轮执行中从未到达 ,那么:
- 执行完 条指令后,机器人必然停在某个非零位置
- 因为没到过 ,所以不会重置,之后就没有指令可执行了
- 因此机器人会在 秒后停止,之后 秒内不会再动
- 答案就是 (因为从未进入 )
所以首先要检查:是否存在 使得 ,并且执行前 条指令后位置变为 。
阶段 2:重置后的循环行为
一旦机器人第一次到达 ,它会立即重置指令指针,从 的第一条指令开始重新执行。
此时机器人在 点,执行一轮完整的 条指令后,它会到达某个新的位置,记作 ( 是执行完整个 后的位移,即 的数量减去 的数量)。
那么从 出发,执行一轮 条指令的路径如下:
- 从 开始
- 执行第 条指令,位置变为
- 执行第 条指令,位置变为
- ...
- 执行第 条指令,位置变为
注意:在这 步过程中,可能会多次经过 点。
这些经过 的时刻(除了起点 本身)也是“进入 点”的事件。
阶段 3:周期重复
从 开始执行完一轮 条指令后:
- 如果 ,那么机器人在一轮结束后回到 ,下一轮又从 开始,行为完全重复
- 如果 ,那么一轮结束后机器人在 (非零),然后因为没有到达 (因为结束位置不是 ),所以不会重置,机器人停止
等等——这里要小心!
根据规则:只有到达 时才重置。
如果一轮结束时位置是 ,那么:- 执行完第 条指令后,机器人在 ,不是
- 没有触发重置
- 没有更多指令可执行(因为执行完了整个序列)
- 所以机器人停止
这意味着:如果机器人从 出发执行一轮后没有回到 ,那么它只会执行这一轮,然后停止。
因此,如果要产生多次进入 的循环,必须满足 ,即一轮的净位移为 。
更准确的分析
实际上,标程采用了一种更巧妙的方法:
-
先尝试到达
从 开始模拟,直到要么到达 ,要么用完 条指令且没到 。
如果 条指令用完还没到 ,答案就是 。 -
如果到达了
设到达 用了 秒。此时:- 已经进入 一次(计入答案)
- 剩余时间 秒
-
重置后,从 开始
从 开始执行指令序列,找出第一次(非起点)到达 的位置。
设从 出发,经过 条指令后第一次回到 ( 可能在 到 之间,也可能不存在)。如果存在这样的 ,那么:
- 每 秒,机器人就会进入 一次
- 在剩余 秒中,这样的周期有 次
- 加上之前的一次,总共 次
如果不存在这样的 (即从 出发后永远不会再回到 ),那么只有第一次到达 的那一次,答案为 。
标程解析
标程的代码逻辑如下:
li n, x, k; cin >> n >> x >> k; string s; cin >> s; // 第一阶段:从 x 出发,尝试到达 0 for (int i = 0; i < n; ++i) { x += (s[i] == 'L' ? -1 : +1); --k; // 消耗 1 秒 if (!x) break; // 到达 0,停止模拟 } li ans = 0; if (!x) { // 如果成功到达 0 ans = 1; // 第一次进入 0 // 第二阶段:从 0 开始,找回到 0 的最小周期 for (int i = 0; i < n; ++i) { x += (s[i] == 'L' ? -1 : +1); if (!x) { ans += k / (i + 1); // 剩余时间能完成多少个完整周期 break; } } } cout << ans << '\n';关键点:
- 第一个循环模拟到第一次到达 ,同时消耗时间
- 如果成功到达, 初始为 , 此时为
- 第二个循环从 开始,找第一次回到 的位置(步数为 )
- 一旦找到,用剩余时间 除以周期长度,得到额外进入次数
- 注意:第二个循环开始时 已经是 ,所以执行第一条指令后 变成 ,然后继续
公式总结
设:
- = 从 到第一次到达 所需的步数(如果存在)
- 如果 不存在,答案为
- 否则,设 = 从 出发后,第一次回到 所需的步数(,如果存在)
- 如果 不存在,答案为
- 如果 存在,答案为
其中 是总时间,实际剩余时间在模拟中已经通过
--k处理,所以代码中直接用k / (i+1)。
复杂度分析
- 每个测试用例模拟最多 步(两次遍历 )
- 所有测试用例的 之和不超过 ,所以总复杂度
- 完全满足时间限制 秒
示例验证
以第二个示例为例:
第一阶段:
- 初始 ,
- 指令1: ,,到达 ,,停止 ,
第二阶段:
- 从 开始(代码中 已被重置为 )
- 指令1: ,(不是 )
- 指令2: ,,到达 ,步数
- ✅
总结
这道题的关键在于:
- 区分“第一次到达 ”和“从 出发后的循环周期”
- 理解重置规则导致只有净位移为 才能产生多次进入
- 通过模拟找到最小周期 ,然后用除法计算完整周期数
标程通过两遍遍历巧妙地解决了问题,避免了显式处理循环和净位移的复杂判断。
- 1
信息
- ID
- 7210
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者