P9370 APIO2023 赛博乐园 / cyberland。
题目就是让我们求一个有各种优惠政策的单源点 \(0\),单汇点 \(H\) 的最短路。优惠政策是:
- 到达能力为 \(2\) 的点,可以让之前走过的距离除以 \(2\)。
- 到达能力为 \(0\) 的点,可以让之前走过的距离直接变成 \(0\)。
有限制:不能经过 \(H\) 多次。那其实也就是说,\(H\) 只能作为答案路径的终点,不能作为路径的途经点。
优惠政策最短路,再加上 97 分中 \(K\) 的限制为 \(K \le 30\),优惠政策能使用的次数很低。
上面加粗的两句正是分层图最短路的两条重要特征。于是想到建立 \(K\) 层的分层图,来解决“除以 \(2\)”这个优惠政策。
这里默认读者已经学会分层图,若不会,请先学习并完成分层图模板:JLOI2011 飞行路线。这里还有分层图题单,供读者练习。
原图为第 \(0\) 层图,总共建立 \(K +1\) 层图(编号 \(0 \sim K\)),第 \(p\) 层的点 \(u\) 代表之前使用优惠恰好 \(p\) 次,到达点 \(u\) 的状态。我们记其为 \((p, u)\)。设它的最短路为 \(\mathrm{dis}(p, u)\)。
最短路算法必须使用 dijkstra,用 spfa 虽然可以通过原题的数据,但复杂度是错的,讨论区中有 hack 数据。
定义 \(w(u, v)\) 为原图上 \(u\) 和 \(v\) 两点之间的边权。如果 \(u\),\(v\) 两点之间没相连接的边则 \(w(u, v)\) 未定义。
思路一
首先想一下,到达能力为 \(0\) 的点可以清空最短路,那其实就相当于从这个点开始走。
因此,我们将所有能从 \(0\) 出发,不途径 \(H\) 到达的,能力同时为 \(0\) 的点看做源点,跑多源最短路即可。
那么能力为 \(0\) 就解决了,现在只需要解决能力 \(2\)。
考虑在 dijkstra 枚举出边时进行如下松弛:
- 尝试用 \(\mathrm{dis}(p, u) + w(u, v)\) 更新