1 条题解
-
0
「雅加达的摩天楼」题解
问题分析
有 只 doge 分布在 座摩天楼上,每只 doge 有初始位置 和跳跃能力 。doge 可以在相邻 倍数的摩天楼间跳跃(即从 到 )。消息可以从一只 doge 传递给同楼的其他 doge。求从 doge 0 到 doge 1 的最少跳跃步数。
核心建模
这是一个图论最短路问题:
- 节点:需要表示 (摩天楼编号, doge信息)
- 边:两种操作对应两种边
- 跳跃:doge 从当前楼跳到另一座楼(消耗1步)
- 传递:doge 将消息传递给同楼的其他 doge(消耗0步)
直接建模的问题
如果为每只 doge 在每个可达的楼都建立节点,节点数可能达到 ,对于 来说太大()。
优化策略:分块思想
观察
- 当 较大时,doge 能到达的楼很少(大约 个)
- 当 较小时,doge 能到达的楼很多,但许多 doge 共享相同的
关键优化
设一个阈值 (约 ,当 时)
1. 对于 的 doge(大跳跃能力)
- 这些 doge 能到达的楼很少(不超过 个)
- 直接建边:从 doge 的每个可达楼建立边
- 每只 doge 最多建立 条边
2. 对于 的 doge(小跳跃能力)
- 这些 doge 能到达很多楼,但 值种类少(只有 种)
- 建立辅助节点:对于每个 ,其中
- 辅助节点表示:在楼 ,以能力 跳跃的状态
3. 边的设计
对于小跳跃能力 doge:
- doge 进入辅助节点:doge 在楼 ,跳跃能力 → 连接到辅助节点 ,边权为
- 从辅助节点跳跃:从 到 ,边权为
- 从辅助节点退出:从 到楼 的所有 doge,边权为
对于大跳跃能力 doge:
- 直接跳跃:从 doge 所在楼 到可达楼 ,边权为 (或建立逐跳的边)
具体实现
数据结构
-
节点编号分配:
- 摩天楼节点: 到
- 辅助节点:对于每个 和每个 ,但实际只需要在访问时动态创建
- doge 节点: 只 doge 作为节点
-
邻接表:存储建好的图
建图过程
步骤1:预处理
- 计算阈值
- 对每只 doge 按 分类
步骤2:为小跳跃能力建图
对于每只 的 doge :
- 添加边:doge → 辅助节点 ,权值
- 辅助节点之间的跳跃边在BFS过程中隐式处理
实际上,我们不需要显式建立所有辅助节点,可以在BFS时动态扩展。
步骤3:为大跳跃能力建图
对于每只 的 doge :
- 直接建立从 开始的所有可达楼的边
- 可以连接到对应楼的 doge 节点
最短路算法
使用 0-1 BFS(双端队列BFS):
- 跳跃边权值为 ,从队尾入队
- 传递边权值为 ,从队首入队
空间优化
辅助节点不需要全部预先建立,可以用:
- 数组
vis[b][p]标记是否访问过状态 - 但 可能仍然太大(),可以接受
算法复杂度分析
时间复杂度
- 大跳跃能力 doge:每只最多建 条边,总共
- 当 ,最坏
- 小跳跃能力 doge:每只建 条边到辅助节点
- BFS:每个节点入队一次
- 总节点数:(辅助节点)
- 约 $30000 + 30000 + 5.2\times 10^6 \approx 5.3\times 10^6$
空间复杂度
- 存储图:
- 在 规模下可接受
注意事项
- 重复 doge:同一座楼可能有多个 doge,包括相同 的
- 直接相遇:如果 doge 0 和 doge 1 初始在同一楼,答案为
- 不可达情况:如果BFS结束后未访问到 doge 1,输出
特殊情况的进一步优化
内存优化技巧
- 使用
vector动态存储邻接表 - 对于辅助节点,使用二维数组
id[b][p]动态分配编号 - 对于大 ,建立边时使用循环,但注意不要重复建立太多边
实际实现细节
算法框架: 1. 读取输入,确定阈值 S = sqrt(N) 2. 为每个 doge 分配节点编号 3. 建立初始边: - 对于 P_i ≤ S:连接 doge_i → (B_i, P_i) 辅助节点 - 对于 P_i > S:从 B_i 向所有可达楼建立边 4. 运行 0-1 BFS 5. 输出答案总结
本题的关键在于通过分块思想处理不同跳跃能力的 doge:
- 小跳跃能力:使用辅助节点共享跳跃状态,避免重复建边
- 大跳跃能力:直接建边,因为每只 doge 的边数有限
这种优化将复杂度从 降低到 ,能够在题目限制内运行。
- 1
信息
- ID
- 5862
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者