C++怎么实现矩阵快速幂_C++线性递推优化【数学】

矩阵快速幂是将整数快速幂的二分乘法逻辑迁移到矩阵运算,需自定义矩阵乘法、正确初始化单位矩阵、按齐次线性递推构造转移矩阵,并在每步乘加中及时取模防溢出。

C++怎么实现矩阵快速幂_C++线性递推优化【数学】

矩阵快速幂的核心就是把 pow 换成矩阵版的二分乘法

普通整数快速幂是用二进制拆分指数,每次平方底数、按位累乘;矩阵快速幂完全照搬这个逻辑,只是把 int 乘法换成矩阵乘法。关键不是“怎么造轮子”,而是“怎么让矩阵乘法能套进快速幂框架里”。

  • 必须自己写 matmul 函数,不能依赖 std::vector 的默认行为——它不支持重载 *,且动态分配开销大
  • 单位矩阵初始化要写对:res[i][i] = 1,其他为 0;别用 memset(res, 1, sizeof(res)) 这种粗暴操作
  • 矩阵大小固定时(比如都是 2x23x3),优先用 std::array<:array long n>, N></:array>,比 vector<vector>></vector> 快 3–5 倍,也避免越界访问

递推式怎么转成转移矩阵?看齐次线性关系的“维数”

不是所有递推都能压成矩阵,只有形如 f(n) = a·f(n−1) + b·f(n−2) + ... 这种无常数项、系数固定的齐次线性递推才行。非齐次(比如带 +1)或非线性(比如 f(n) = f(n−1) * f(n−2))得先变形或放弃。

  • f(n) = f(n−1) + f(n−2) → 需要 2 维状态:[f(n), f(n−1)]^T,转移矩阵是 {{1,1},{1,0}}
  • f(n) = 2*f(n−1) − f(n−2) + 3 → 含常数项,得升一维:状态扩成 [f(n), f(n−1), 1]^T,最后一行补 [0,0,1] 来维持常数 1 不变
  • 初始向量顺序必须和转移矩阵行列严格对应,错一位结果全乱——常见错误是把 [f(1), f(0)] 写成 [f(0), f(1)]

模运算下容易爆 long long?乘法中间结果必须及时取模

矩阵乘法本质是大量 a[i][k] * b[k][j] 累加,哪怕单个元素 ≤ 1e9,相乘就可能到 1e18,再加几次直接溢出。C++ 没有自动模乘,必须手动控制。

  • 不要只在最后 % MOD,要在每一步乘加后都做:sum = (sum + 1LL * a[i][k] * b[k][j]) % MOD
  • 1LL * 强制提升为 long long,否则 int * int 先溢出再转,没用
  • 如果 MOD 接近 2^31,连 1LL * a * b 都可能超 2^63−1,这时得用 __int128(GCC 支持)或龟速乘(不推荐,慢 10 倍)

为什么有时结果不对?检查这三个地方

矩阵快速幂代码短,但错一个下标或漏一次取模,输出就是错的,而且很难 debug。最常卡在:

立即学习C++免费学习笔记(深入)”;

  • 快速幂循环里写成了 while (n > 0) 却忘了 n >>= 1,死循环
  • 转移矩阵行列搞反了:左乘还是右乘?标准是 res = M^k * init,所以矩阵乘法实现必须是 A * B 表示“先 B 后 A”作用,别颠倒
  • 初始向量维度和矩阵不匹配:比如 3×3 矩阵配了 2×1 向量,编译不报错但运行时内存踩踏,值全乱

实际写的时候,先手算小样例(比如斐波那契第 5 项),把每一步矩阵和向量打印出来,比对着看哪步开始偏移,比瞎猜快得多。