[CF 2073D] Tower of Hanoi
好题
思路
题意
给定 表示大小为 的圆盘在第几根柱子
圆盘大小是一个排列
一个问题被定义为, 只考虑 , 也就是对于大小从 到 之间的圆盘, 把这些盘子全部移到 柱所需最小花费
一次修改被定义为, 把
先考虑一次询问
感性上来理解, 我们如何把一堆圆盘丢到 \(1\) 柱上相当于把一堆圆盘从 \(1\) 柱上丢进原位置
不难发现大概是这样一个过程
- 按圆盘大小从大往小考虑
- 如果当前圆盘已经在目标柱了, 可以不管
- 否则把当前圆盘上面那一堆移到辅助柱子, 然后把当前圆盘丢到目标柱子, 当前圆盘就处理完了
根据汉诺塔性质, 一次 \(3\) 操作花费为 \(2^{x}\) , 其中 \(x\) 是上面那一堆的大小
这样可以 \(\mathcal{O} (n)\) 做完一次询问
修改单点, 不难想到矩阵线段树, 因此我们考虑用矩阵表示一个位置的贡献
记 \(ans, pos\) 表示当前的花费, 当前的位置, 修改柱子编号为 \(\{0, 1, 2\}\) 方便处理
最初 \(ans = 0, pos = 1\)
对于 \(p_i\) , 其修改为
\[ans \gets ans + [pos \neq p_i] \times 2^{i - L} \\
pos \gets \big(3 - p_i - pos\big) \textrm{ mod } 3
\]
发现这样并非可以封装成矩阵
不妨用 \(ans_0, ans_1, ans_2\) 表示把之前\((\)更小的圆盘\()\)及 \(i\) 圆盘堆到一起, 并且这些的圆盘放在了 \(0/1/2\) 三根柱子上的最小步数
转移不难想出
也就是
\[\begin{align*}
ans_j \gets
\begin{cases}
{ans'}_j, \textrm{ case } j = p_i \\
{ans'}_{(3 - p_i - j) \textrm{ mod } 3} + 2^{x}, \textrm{ otherwise}
\end{cases}
\end{align*}\]
这个就不难转移了
不再赘述
但是这个转移基于一个汉诺塔的性质
直接把一堆东西丢到将要使用它的地方, 而不是再花费新的步数把一堆东西丢到将要使用它的地方一定最优
总结
汉诺塔问题常用的方法
- 分治
- 从大到小考虑
- 辅助柱子
- 先把其它东西丢到辅助圆盘在移动当前圆盘最优
一类很典的矩阵线段树题目, 但并非会做
当转移不好用矩阵表示的时候, 考虑转成 \(\rm{dp}\) 多考虑一点情况去做

浙公网安备 33010602011771号