1 条题解
-
0
好的,我们基于之前的逻辑和代码,给出这道的详细题解。
题目重述
我们有一条无限长的带子(坐标从 到 ,两端之外视为离开),上面有 个交通灯,位置 。
每个灯 有延迟 ()。
灯在全局时间 显示红灯当且仅当
[ t \bmod k = d_i ] 否则显示绿灯。你在 时刻位于某个起始位置 ,面向正方向(坐标增大的方向)。
每个时刻的顺序操作:- 如果当前位置是红灯 → 转身(方向取反)。
- 朝当前方向移动 格。
问:能否在有限时间( 秒内)离开带子(即到达 或 以后)。
关键难点
- 位置范围极大(),不能直接模拟每一格。
- 但灯的个数 ,所以关键事件只在灯的位置发生。
- 灯的规律由时间模 决定,。
核心思想
状态压缩:运动的“关键状态”是到达某个灯的时刻。
在灯与灯之间的大段距离中,不会发生任何状态变化(没有灯,所以方向不变,时间线性增长)。因此我们只需模拟“到达灯的时刻”。
状态定义
每个灯可以看作一个“反射点”。
状态为: [ (i, \text{dir}) ] 表示我们位于灯 的位置,正准备离开它朝方向 ( 表示向右, 表示向左)。初始状态不是“位于灯上”,而是在某个起始位置 ,方向 ,但我们可先移动到第一个遇到的灯。
转移规则
假设我们处于状态 ,当前全局时间为 (到达灯 的时刻)。
情况 1:(向右)
下一个可能到达的灯是 (如果 ),否则是右边界(离开)。
到达灯 的时间: [ T' = T + (p_{i+1} - p_i) ]
检查是否红灯: [ \text{red} = (T' \bmod k == d_{i+1}) ]
- 如果是红灯 → 方向变为 (向左),新状态 。
- 如果是绿灯 → 方向保持 ,继续向右。但此时已在灯 上,且绿灯,所以不会反弹,下一盏是 。
因此等价于转移到 ,但注意到达 时未反弹,所以时间就是 。
边界情况( 即最右灯):
- 如果向右无灯,则到达右边界的时间 ,一定会离开 → YES。
情况 2:(向左)
类似,到达 的时间: [ T' = T + (p_i - p_{i-1}) ] 检查 :
- 红灯 → 方向变为 ,新状态 。
- 绿灯 → 方向保持 ,继续向左,新状态 。
边界:若 (最左灯),向左无灯,到达左边界时间 ,一定离开 → YES。
算法流程
对于每个查询 :
-
找到 右边的第一个灯(可能没有)。
- 如果没有 → 直接离开 → YES。
- 如果有,计算到达它的时间 。
-
从该灯开始模拟状态转移,用
visited[i][dir]记录是否访问过。 -
如果遇到边界 → YES。
-
如果遇到重复状态(即已访问的 )且不是边界 → NO(进入死循环)。
复杂度分析
- 状态数:。
- 转移时间 。
- 每个查询最多经过 步就重复或离开。
- 总复杂度 ,因 总和与 总和 ,完全可接受。
示例推演(题目第一个样例)
起始在 ,即灯 0 的位置,。
灯 0 在 时: → 绿灯,方向不变 。
到达灯 1(),时间 , → 绿灯,方向 ,继续向右无灯 → 离开 → YES。
代码对应
之前给出的 C++ 代码实现了这个模拟,核心就是跳过大区间、只在灯处判断红绿、检测重复状态。
总结
- 通过仅考虑灯的位置作为关键点,避免了大范围模拟。
- 利用 小的特点,用模 判断红绿灯。
- 用访问标记检测无限循环。
- 边界处理 = 离开条件。
这就将原来的连续大尺度问题转化为有限状态机的可达性问题。
- 1
信息
- ID
- 7107
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者