Skip to content

矩阵快速幂 笔记 ​

一、简单介绍 ​

一个 m×n 的矩阵 A 可以和一个 n×p 的矩阵 B 相乘,得到一个大小为 n×p 的矩阵 C,其中:

Ci,j=∑k=1nAi,k×Bk,j

那么就可以用快速幂求矩阵幂了。

二、简单应用 ​

1. P1962 斐波那契数列 ​

f1=f2=1,fi=fi−1+fi−2,求 fnmod109+7。

我们假设矩阵 [fi−1fi] 乘上某一个矩阵之后可以得到 [fifi+1],由于 fi=0×fi−1+1×fi,fi+1=1×fi−1+1×fi,所以:

[fi−1fi]×[0111]=[fifi+1]

矩阵快速幂解决即可。

2. 数列 ​

f1=f2=0,fi=7×fi−1+6×fi−2+4×3i+5×i,求 fnmod109+7。

同理,假设矩阵 [fi−1fi4×3i5×i5] 乘上某一个矩阵可以得到 [fifi+14×3i+15×(i+1)5]。

由于:

{fi=1×fifi+1=6×fi+7×fi−1+3×4×3i+1×5×i+1×54×3i+1=3×4×3i5×(i+1)=1×5×i+1×55=1×5

所以:

[fi−1fi4×3i5×i5]×[0600017000033000101001011]=[fifi+14×3i+15×(i+1)5]

3. CF691E Xor-sequences ​

给定一个数集 A,现在你需要构造一个长度为 k 的序列 B,序列 B 的元素从数集 A 中任意挑选,要求 B 中任意相邻的两个数字的异或值二进制表示中 1 的个数是 3 的倍数,求方案数,对 109+7 取模。

1≤n≤100,1≤k,ai≤1018。

设 fi,j 表示当 B 序列长度为 i,且最后一个选 j 的方案数,p(x) 表示 x 在二进制下 1 的个数,则:

fi+1,j=∑k=1nfi,k[3∣p(aj⊕ak)]

最终答案即为 ∑i=1nfn,i。

考虑优化,由于每一个 j 都只能从固定的某几个 k 转移而来(因为 aj⊕ak 的值与 i 无关),所以考虑矩阵加速。

假设 [fi,1fi,2fi,3…fi,n] 乘上某个矩阵可以得到 [fi+1,1fi+1,2fi+1,3…fi+1,n],c(j,k) 表示 3∣p(aj⊕ak)。根据上面的状态转移方程,这是一个 n×n 的矩阵,第 i 行第 j 列的值就是 c(i,j),写个函数即可。

cpp
matrix b(n, n, false);
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++) b.d[i][j] = check(a[i], a[j]);
b = pow_matrix(b, k - 1);
int ans = 0;
for (int i = 1; i <= n; i++)
    for (int j = 1; j <= n; j++) ans = (ans + b.d[i][j]) % mod;
cout << ans;

4. P3176 [HAOI2015] 数字串拆分 ​

本文原在 2025-04-07 18:03 发布于本人洛谷博客。

由于 f(s) 的拆分方式不关心顺序,故有 f(i)=∑j∈[i−m,i)f(j)(f(0)=1),可理解为在 f(j) 的拆分基础上,添加一个大小为 (i−j) 的数。

那么构造矩阵 Fi=[f(i)f(i−1)f(i−2)⋯f(i−m+1)],矩阵快速幂转移即可求出 f(i)=Fi(1,1),假设转移矩阵为 A,那么有 Fi=F0×Ai。

由初中数学知识,Fx+y+Fz+w=F0×(Ax×Ay+Az×Aw),故 g(s) 就相当于将字符串 s 拆成若干段,每一段的转移矩阵相乘,不同拆法的转移矩阵相加。设 Gi 表示 s 前 i 位的转移矩阵,则有转移 Gi=∑j∈[1,i]Gj−1×As[j:i]。

但是 |s|≤500,As[j:i] 将会涉及指数高精。考虑递推求出所有的 As[j:i],可以将 s[j:i] 拆位,先求出每个数码的转移矩阵。设 Bi,j=Ai×10j,递推可求。接着设 Cj,i 表示 s[j:i] 的转移矩阵,则有 Cj,i=Cj+1,i×Bsj,i−j。

最终答案即为 (F0×G|s|)(1,1)。

忽略矩阵乘法,求 B 时间 O(10×|s|),求 C 时间 O(|s|2),求 G 时间 O(|s|2)。瓶颈在求 C,G,时间复杂度为 O(m3|s|2),可以通过。

最近更新