矩阵快速幂原理

可以这样来理解“矩阵快速幂”的思路,它其实源自于任何“幂运算”都满足这样两条关键性质:

  1. 结合律\((A^x)\times(A^y)=A^{x+y}\)
  2. 平方技巧\((A^x)^2=A^{2x}\)

把要算的指数 \(t\) 用二进制展开:

\[t = b_0\cdot2^0 + b_1\cdot2^1 + b_2\cdot2^2 + \cdots + b_k\cdot2^k, \]

其中每个 \(b_i\in\{0,1\}\)。那么

\[A^t \;=\; A^{b_0\cdot2^0}\times A^{b_1\cdot2^1}\times\cdots\times A^{b_k\cdot2^k}. \]

每一项要么是 \(A^{2^i}\)(当 \(b_i=1\)),要么是“1”(当 \(b_i=0\))。


如何高效地得到所有 \(A^{2^i}\)

\(A^{2^i}\) 本身又满足:

\[A^{2^i} \;=\; (A^{2^{i-1}})^2. \]

也就是说,只要从 \(A^{2^0}=A\)(也就是底数自己)开始,每次做一个“平方”操作,就能依次得到

\[A^{2^1},\quad A^{2^2},\quad A^{2^3},\ \dots \]

用掉哪一位的 \(2^i\),就把对应的 \(A^{2^i}\) “乘”到结果里。


带着二进制『高效筛』来走一遍

  1. 初始化

    • 结果矩阵 res = I(对应二进制中所有 \(b_i=0\) 时的“空乘积”)。
    • 底数矩阵 base = A(对应 \(2^0\))。
  2. 处理每一位

    • 看当前 \(t\) 的最低位(即 \(b_0\)):

      • 如果是 1,就做 res = res × base,把这份 \(2^0\) 的幂累加到最后答案里。
      • 如果是 0,就跳过。
    • 再做 base = base × base,这样 base\(A^{2^i}\)\(A^{2^{i+1}}\)

    • 然后把 \(t\) 右移一位(相当于把二进制 “抛弃” 刚才处理过的那一位),继续处理下一位。

  3. 终止

    • \(t\) 被右移到 0 时,所有二进制位都检查过了,res 自然就积累了所有需要的 \(A^{2^i}\) 因子,正好等于 \(A^t\)

为什么会“想”到这个方法?

  • 从“看指数二进制”开始:我们常常在做大数的幂(如快速幂、快速幂取模)时,会把指数拆成二进制权重的和,因为任何整数都可以分解成 \(2^i\) 的和。
  • 利用平方加速:把一次次「乘一个 A」升格为「平方」可以让指数增长速度成倍攀升——\(1,2,4,8,16,\dots\),这样只要 \(\log_2 t\) 步就能覆盖到 \(t\)
  • 结果累积:遇到二进制 1 就累一次乘,最终把所有“被选中的”倍数相乘,合在一起就得到精确的 \(A^t\)

这个思路不仅能用在矩阵上,任何满足结合律的“乘法”都可以这么做(整数取模、函数迭代、状态转移……),是计算“\(\text{some\_operation}^t\)”时的一个万能加速套路。

posted @ 2025-05-14 16:32  ijpq  阅读(29)  评论(0)    收藏  举报