Loading

[CF 2073D] Tower of Hanoi

好题

思路

题意

给定 pip_i 表示大小为 ii 的圆盘在第几根柱子 (pi{1,2,3})\Big(p_i \in \{1, 2, 3\}\Big)
圆盘大小是一个排列

一个问题被定义为, 只考虑 p[L,R]p_{[L, R]} , 也就是对于大小从 LLRR 之间的圆盘, 把这些盘子全部移到 11 柱所需最小花费

一次修改被定义为, 把 pxyp_x \gets y

先考虑一次询问
感性上来理解, 我们如何把一堆圆盘丢到 \(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}\) 多考虑一点情况去做

posted @ 2025-03-05 10:59  Yorg  阅读(16)  评论(0)    收藏  举报