矩阵快速幂
文章目录
对于方阵 M M M,在计算其 n n n 次幂 M n M^n Mn 时,传统的做法是,依次将 n n n 个 M M M 相乘,但是这样计算起来的效率并不高,时间复杂度为 O ( n ) O(n) O(n),而矩阵快速幂可以加速矩阵幂的计算。
矩阵快速幂
原理
将
n
n
n 转为二进制,
n
=
(
b
k
b
k
−
1
.
.
.
b
2
b
1
b
0
)
2
=
b
k
⋅
2
k
+
b
k
−
1
⋅
2
k
−
1
+
.
.
.
+
b
2
⋅
2
2
+
b
1
⋅
2
1
+
b
0
⋅
2
0
n=(b_kb_{k-1}...b_2b_1b_0)_2=b_k\cdot 2^k+b_{k-1}\cdot 2^{k-1}+...+b_2\cdot 2^2+b_1\cdot 2^1+b_0\cdot 2^0
n=(bkbk−1...b2b1b0)2=bk⋅2k+bk−1⋅2k−1+...+b2⋅22+b1⋅21+b0⋅20,则
M
n
=
M
b
k
⋅
2
k
+
b
k
−
1
⋅
2
k
−
1
+
.
.
.
+
b
2
⋅
2
2
+
b
1
⋅
2
1
+
b
0
⋅
2
0
=
M
b
k
⋅
2
k
⋅
M
b
k
−
1
⋅
2
k
−
1
⋅
.
.
.
⋅
M
b
2
⋅
2
2
⋅
M
b
1
⋅
2
1
⋅
M
b
0
⋅
2
0
⋅
M^n=M^{b_k\cdot 2^k+b_{k-1}\cdot 2^{k-1}+...+b_2\cdot 2^2+b_1\cdot 2^1+b_0\cdot 2^0}=M^{b_k\cdot 2^k}\cdot M^{b_{k-1}\cdot 2^{k-1}}\cdot ...\cdot M^{b_2\cdot 2^2}\cdot M^{b_1\cdot 2^1}\cdot M^{b_0\cdot 2^0}\cdot
Mn=Mbk⋅2k+bk−1⋅2k−1+...+b2⋅22+b1⋅21+b0⋅20=Mbk⋅2k⋅Mbk−1⋅2k−1⋅...⋅Mb2⋅22⋅Mb1⋅21⋅Mb0⋅20⋅
对于上面的式子,我们可以发现一些有用信息:
- 若 b i = 0 ( 0 ⩽ i ⩽ k ) b_i=0 \ \ (0\leqslant i\leqslant k) bi=0 (0⩽i⩽k),则 M b i ⋅ 2 i = 1 M^{b_i\cdot 2^i}=1 Mbi⋅2i=1
- ( M 2 i ) 2 = M 2 i + 1 ( 0 ⩽ i < k ) (M^{2^i})^2=M^{2^{i+1}} \ \ (0\leqslant i < k) (M2i)2=M2i+1 (0⩽i<k)
计算过程
伪代码:
求 M n M^n Mn, n = ( b k b k − 1 . . . b 2 b 1 b 0 ) 2 n=(b_kb_{k-1}...b_2b_1b_0)_2 n=(bkbk−1...b2b1b0)2
- ① r e s u l t = E (单位矩阵) result=\mathbb{E}\text{(单位矩阵)} result=E(单位矩阵)
- ② 从低位到高位遍历
n
n
n 的二进制
(
b
k
b
k
−
1
.
.
.
b
2
b
1
b
0
)
2
(b_kb_{k-1}...b_2b_1b_0)_2
(bkbk−1...b2b1b0)2
- 若 b i = 1 ( 0 ⩽ i ⩽ k ) b_i=1 \ \ (0\leqslant i\leqslant k) bi=1 (0⩽i⩽k), r e s u l t = r e s u l t ∗ M result=result*M result=result∗M
- M = M ∗ M M=M*M M=M∗M
- ③ 遍历结束,返回 r e s u l t result result
示例:
M = [ 1 1 1 0 ] M=\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} M=[1110], n = 5 n=5 n=5,求 M n M^n Mn
- ① r e s u l t = [ 1 0 0 1 ] result=\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} result=[1001]
- ② 从低位到高位遍历
n
n
n 的二进制
b
2
b
1
b
0
=
(
101
)
2
b_2b_1b_0=(101)_2
b2b1b0=(101)2
-
b
0
=
1
b_0=1
b0=1
r e s u l t = r e s u l t ∗ M = [ 1 0 0 1 ] [ 1 1 1 0 ] = [ 1 1 1 0 ] result=result*M=\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}=\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} result=result∗M=[1001][1110]=[1110] M = M ∗ M = [ 1 1 1 0 ] [ 1 1 1 0 ] = [ 2 1 1 1 ] M=M*M=\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}=\begin{bmatrix} 2 & 1 \\ 1 & 1 \end{bmatrix} M=M∗M=[1110][1110]=[2111] -
b
1
=
0
b_1=0
b1=0
M = M ∗ M = [ 2 1 1 1 ] [ 2 1 1 1 ] = [ 5 3 3 2 ] M=M*M=\begin{bmatrix} 2 & 1 \\ 1 & 1 \end{bmatrix}\begin{bmatrix} 2 & 1 \\ 1 & 1 \end{bmatrix}=\begin{bmatrix} 5 & 3 \\ 3 & 2 \end{bmatrix} M=M∗M=[2111][2111]=[5332] -
b
2
=
1
b_2=1
b2=1
r e s u l t = r e s u l t ∗ M = [ 1 1 1 0 ] [ 5 3 3 2 ] = [ 8 5 5 3 ] result=result*M=\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}\begin{bmatrix} 5 & 3 \\ 3 & 2 \end{bmatrix}=\begin{bmatrix} 8 & 5 \\ 5 & 3 \end{bmatrix} result=result∗M=[1110][5332]=[8553] M = M ∗ M = [ 5 3 3 2 ] [ 5 3 3 2 ] = [ 34 21 21 13 ] M=M*M=\begin{bmatrix} 5 & 3 \\ 3 & 2 \end{bmatrix}\begin{bmatrix} 5 & 3 \\ 3 & 2 \end{bmatrix}=\begin{bmatrix} 34 & 21 \\ 21 & 13 \end{bmatrix} M=M∗M=[5332][5332]=[34212113]
-
b
0
=
1
b_0=1
b0=1
- ③ 遍历结束,返回 r e s u l t = [ 8 5 5 3 ] result=\begin{bmatrix} 8 & 5 \\ 5 & 3 \end{bmatrix} result=[8553]
算法
vector<vector<int>> matrixMultiple(const vector<vector<int>>& left,const vector<vector<int>>& right){
int leftRows=left.size();
int count=left[0].size();
int rightColumns=right[0].size();
vector<vector<int>> result(leftRows,vector<int>(rightColumns));
for(int i=0;i<leftRows;++i){
for(int j=0;j<rightColumns;++j){
for(int k=0;k<count;++k){
result[i][j]+=(left[i][k]*right[k][j]);
}
}
}
return result;
};
vector<vector<int>> matrixQuickPow(vector<vector<int>> m,int n){ //求方阵m的n次幂
int rows=m.size();
vector<vector<int>> result(rows,vector<int>(rows));
for(int i=0;i<rows;++i){
result[i][i]=1;
}
while(n>0){
if(n&1){
result=matrixMultiple(result,m);
}
n>>=1;
m=matrixMultiple(m,m);
}
return result;
}
复杂度分析
求 M n M^n Mn
- 时间复杂度: O ( log n ) O(\log n) O(logn),原本要进行 n − 1 n-1 n−1 次矩阵乘法,使用矩阵快速幂后只用 log 2 ( n ) \log_2(n) log2(n) 次。
矩阵快速幂的应用场景
有线性齐次递推式形如
f
(
n
)
=
∑
i
=
1
m
a
i
f
(
n
−
i
)
f(n) = \sum\limits_{i=1}^m a_if(n-i)
f(n)=i=1∑maif(n−i),我们就可以把这个递推式写成矩阵的形式,首先构造出一个矩阵
M
M
M,这是一个
m
∗
m
m*m
m∗m 的方阵,一般情况下,可以令
M
=
[
a
1
a
2
a
3
⋯
a
m
−
1
a
m
1
0
0
⋯
0
0
0
1
0
⋯
0
0
0
0
1
⋯
0
0
⋮
⋮
⋮
⋱
⋮
⋮
0
0
0
⋯
1
0
]
M=\begin{bmatrix} a_{1} & a_{2} & a_{3} & \cdots & a_{m-1} & a_m\\ 1 & 0 & 0 & \cdots & 0 & 0\\ 0 & 1 & 0 & \cdots & 0 &0 \\ 0 & 0 & 1 & \cdots & 0 & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & 0 & \cdots & 1 &0 \end{bmatrix}
M=⎣⎢⎢⎢⎢⎢⎢⎢⎡a1100⋮0a2010⋮0a3001⋮0⋯⋯⋯⋯⋱⋯am−1000⋮1am000⋮0⎦⎥⎥⎥⎥⎥⎥⎥⎤
然后可以得到
f
(
n
)
=
∑
i
=
1
m
a
i
f
(
n
−
i
)
f(n) = \sum\limits_{i=1}^m a_if(n-i)
f(n)=i=1∑maif(n−i) 的矩阵形式:
[
f
(
n
+
1
)
f
(
n
)
f
(
n
−
1
)
f
(
n
−
2
)
⋮
f
(
n
−
m
)
]
=
[
a
1
a
2
a
3
⋯
a
m
−
1
a
m
1
0
0
⋯
0
0
0
1
0
⋯
0
0
0
0
1
⋯
0
0
⋮
⋮
⋮
⋱
⋮
⋮
0
0
0
⋯
1
0
]
[
f
(
n
)
f
(
n
−
1
)
f
(
n
−
2
)
f
(
n
−
3
)
⋮
f
(
n
−
m
−
1
)
]
\begin{bmatrix} f(n+1) \\ f(n) \\ f(n-1) \\ f(n-2) \\ \vdots \\ f(n-m) \end{bmatrix}=\begin{bmatrix} a_{1} & a_{2} & a_{3} & \cdots & a_{m-1} & a_m\\ 1 & 0 & 0 & \cdots & 0 & 0\\ 0 & 1 & 0 & \cdots & 0 &0 \\ 0 & 0 & 1 & \cdots & 0 & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & 0 & \cdots & 1 &0 \end{bmatrix}\begin{bmatrix} f(n) \\ f(n-1) \\ f(n-2) \\ f(n-3) \\ \vdots \\ f(n-m-1) \end{bmatrix}
⎣⎢⎢⎢⎢⎢⎢⎢⎡f(n+1)f(n)f(n−1)f(n−2)⋮f(n−m)⎦⎥⎥⎥⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎢⎢⎡a1100⋮0a2010⋮0a3001⋮0⋯⋯⋯⋯⋱⋯am−1000⋮1am000⋮0⎦⎥⎥⎥⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎢⎢⎢⎡f(n)f(n−1)f(n−2)f(n−3)⋮f(n−m−1)⎦⎥⎥⎥⎥⎥⎥⎥⎤
=
M
[
f
(
n
)
f
(
n
−
1
)
f
(
n
−
2
)
f
(
n
−
3
)
⋮
f
(
n
−
m
−
1
)
]
=
M
2
[
f
(
n
−
1
)
f
(
n
−
2
)
f
(
n
−
3
)
f
(
n
−
4
)
⋮
f
(
n
−
m
−
2
)
]
=
.
.
.
=
M
j
+
1
[
f
(
n
−
j
)
f
(
n
−
j
−
1
)
f
(
n
−
j
−
2
)
f
(
n
−
j
−
3
)
⋮
f
(
n
−
j
−
m
−
1
)
]
=M\begin{bmatrix} f(n) \\ f(n-1) \\ f(n-2) \\ f(n-3) \\ \vdots \\ f(n-m-1) \end{bmatrix}= M^2\begin{bmatrix} f(n-1) \\ f(n-2) \\ f(n-3) \\ f(n-4) \\ \vdots \\ f(n-m-2) \\ \end{bmatrix}=...= M^{j+1}\begin{bmatrix} f(n-j) \\ f(n-j-1) \\ f(n-j-2) \\ f(n-j-3) \\ \vdots \\ f(n-j-m-1) \\ \end{bmatrix}
=M⎣⎢⎢⎢⎢⎢⎢⎢⎡f(n)f(n−1)f(n−2)f(n−3)⋮f(n−m−1)⎦⎥⎥⎥⎥⎥⎥⎥⎤=M2⎣⎢⎢⎢⎢⎢⎢⎢⎡f(n−1)f(n−2)f(n−3)f(n−4)⋮f(n−m−2)⎦⎥⎥⎥⎥⎥⎥⎥⎤=...=Mj+1⎣⎢⎢⎢⎢⎢⎢⎢⎡f(n−j)f(n−j−1)f(n−j−2)f(n−j−3)⋮f(n−j−m−1)⎦⎥⎥⎥⎥⎥⎥⎥⎤
若我们知道
[
f
(
n
−
j
)
f
(
n
−
j
−
1
)
f
(
n
−
j
−
2
)
f
(
n
−
j
−
3
)
⋮
f
(
n
−
j
−
m
−
1
)
]
\begin{bmatrix} f(n-j) \\ f(n-j-1) \\ f(n-j-2) \\ f(n-j-3) \\ \vdots \\ f(n-j-m-1) \\ \end{bmatrix}
⎣⎢⎢⎢⎢⎢⎢⎢⎡f(n−j)f(n−j−1)f(n−j−2)f(n−j−3)⋮f(n−j−m−1)⎦⎥⎥⎥⎥⎥⎥⎥⎤ 的取值,就可以使用矩阵快速幂求出
M
j
+
1
M^{j+1}
Mj+1,然后可以得到
[
f
(
n
+
1
)
f
(
n
)
f
(
n
−
1
)
f
(
n
−
2
)
⋮
f
(
n
−
m
)
]
\begin{bmatrix} f(n+1) \\ f(n) \\ f(n-1) \\ f(n-2) \\ \vdots \\ f(n-m) \end{bmatrix}
⎣⎢⎢⎢⎢⎢⎢⎢⎡f(n+1)f(n)f(n−1)f(n−2)⋮f(n−m)⎦⎥⎥⎥⎥⎥⎥⎥⎤