矩阵快速幂原理
可以这样来理解“矩阵快速幂”的思路,它其实源自于任何“幂运算”都满足这样两条关键性质:
- 结合律:\((A^x)\times(A^y)=A^{x+y}\)。
- 平方技巧:\((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}\) “乘”到结果里。
带着二进制『高效筛』来走一遍
-
初始化
- 结果矩阵
res = I(对应二进制中所有 \(b_i=0\) 时的“空乘积”)。 - 底数矩阵
base = A(对应 \(2^0\))。
- 结果矩阵
-
处理每一位
-
看当前 \(t\) 的最低位(即 \(b_0\)):
- 如果是 1,就做
res = res × base,把这份 \(2^0\) 的幂累加到最后答案里。 - 如果是 0,就跳过。
- 如果是 1,就做
-
再做
base = base × base,这样base从 \(A^{2^i}\) → \(A^{2^{i+1}}\)。 -
然后把 \(t\) 右移一位(相当于把二进制 “抛弃” 刚才处理过的那一位),继续处理下一位。
-
-
终止
- 当 \(t\) 被右移到 0 时,所有二进制位都检查过了,
res自然就积累了所有需要的 \(A^{2^i}\) 因子,正好等于 \(A^t\)。
- 当 \(t\) 被右移到 0 时,所有二进制位都检查过了,
为什么会“想”到这个方法?
- 从“看指数二进制”开始:我们常常在做大数的幂(如快速幂、快速幂取模)时,会把指数拆成二进制权重的和,因为任何整数都可以分解成 \(2^i\) 的和。
- 利用平方加速:把一次次「乘一个 A」升格为「平方」可以让指数增长速度成倍攀升——\(1,2,4,8,16,\dots\),这样只要 \(\log_2 t\) 步就能覆盖到 \(t\)。
- 结果累积:遇到二进制 1 就累一次乘,最终把所有“被选中的”倍数相乘,合在一起就得到精确的 \(A^t\)。
这个思路不仅能用在矩阵上,任何满足结合律的“乘法”都可以这么做(整数取模、函数迭代、状态转移……),是计算“\(\text{some\_operation}^t\)”时的一个万能加速套路。
本文来自博客园,作者:ijpq,转载请注明原文链接:https://www.cnblogs.com/ijpq/p/18876149

浙公网安备 33010602011771号