先导知识
- 矩阵乘法
[ a b c d ] ∗ [ e f g h ] = [ a e + b g a f + b h c e + d g c f + d h ] \begin{bmatrix} a & b \\ c & d \end{bmatrix} * \begin{bmatrix} e & f \\ g & h \end{bmatrix} = \begin{bmatrix} ae+bg & af+bh \\ ce+dg & cf+dh \end{bmatrix} [acbd]∗[egfh]=[ae+bgce+dgaf+bhcf+dh]
由此可见矩阵乘法不满足交换律! - 单位矩阵(矩阵对角线为1,其余都为0,常用E表示)
[ 1 0 0 . . . 0 0 1 0 . . . 0 0 0 1 . . . 0 . . . . . . . . . 0 0 0 0 1 ] \begin{bmatrix} 1 & 0 & 0 & ... & 0 \\ 0 & 1 & 0 &... & 0 \\ 0 & 0 & 1 & ... & 0\\ & ... & ... & ...\\ 0 & 0 & 0 & 0 &1 \end{bmatrix} ⎣⎢⎢⎢⎢⎡1000010...0001...0............00001⎦⎥⎥⎥⎥⎤
单位矩阵在矩阵世界里相当于常数中的1,任何矩阵乘单位矩阵都等于该矩阵本身
OK, 接下来进入正题
如何用矩阵优化递推
举例子永远是最好理解新知识的方法。
斐波那契数列,不懂得可以百度一下。主要是说一个数列,前两项为1,从第3项开始数列的值为前两项之和。
用函数表示为:
F
i
b
(
n
)
=
{
1
n<=2
F
i
b
(
n
−
1
)
+
F
i
b
(
n
−
2
)
n > 2
Fib(n) = \begin{cases} 1 &\text{n<=2} \\ Fib(n-1)+Fib(n-2)&\text{n > 2} \end{cases}
Fib(n)={1Fib(n−1)+Fib(n−2)n<=2n > 2
有了递推公式,相信求出斐波那契数列的第n项是多少,用递推很好求出来。但是当n大于
1
0
18
10^{18}
1018时,递推就会超时。
所以接下来介绍另一种求法。
我们从递推公式可以看出,当
n
<
=
2
n<=2
n<=2的时候,
F
i
b
(
1
)
=
F
i
b
(
2
)
=
1
Fib(1)=Fib(2) = 1
Fib(1)=Fib(2)=1,那么就可以构造一个Base矩阵作为起始矩阵。
B
a
s
e
=
[
1
1
]
Base = \begin{bmatrix} 1& 1 \end{bmatrix}
Base=[11]
当
n
>
2
n>2
n>2时
F
i
b
(
n
)
Fib(n)
Fib(n) 是由
F
i
b
(
n
−
1
)
Fib(n-1)
Fib(n−1) 和
F
i
b
(
n
−
2
)
Fib(n-2)
Fib(n−2) 决定的。
那么我们就可以构造一个状态转移矩阵 T。
[
F
i
b
(
n
−
1
)
F
i
b
(
n
−
2
)
]
∗
[
1
1
]
\begin{bmatrix} Fib(n-1) & Fib(n-2) \end{bmatrix} * \begin{bmatrix} 1\\ 1 \end{bmatrix}
[Fib(n−1)Fib(n−2)]∗[11]
=
F
i
b
(
n
−
1
)
+
F
i
b
(
n
−
2
)
= Fib(n-1)+Fib(n-2)
=Fib(n−1)+Fib(n−2)
=
F
i
b
(
n
)
= Fib(n)
=Fib(n)
而求
F
i
b
(
n
+
1
)
Fib(n+1)
Fib(n+1)需要
F
i
b
(
n
)
Fib(n)
Fib(n)和
F
i
b
(
n
−
1
)
Fib(n-1)
Fib(n−1),所以还需要求一下
F
i
b
(
n
−
1
)
Fib(n-1)
Fib(n−1)。
[
F
i
b
(
n
−
1
)
F
i
b
(
n
−
2
)
]
∗
[
1
0
]
\begin{bmatrix} Fib(n-1) & Fib(n-2) \end{bmatrix} * \begin{bmatrix} 1\\ 0 \end{bmatrix}
[Fib(n−1)Fib(n−2)]∗[10]
=
F
i
b
(
n
−
1
)
= Fib(n-1)
=Fib(n−1)
所以这个 T 矩阵就是:
[
1
1
1
0
]
\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}
[1110]
至此,当你求斐波那契数列的第五项时,对应的矩阵公式就是:
B
a
s
e
∗
T
3
=
[
1
1
]
∗
[
1
1
1
0
]
3
=
[
F
i
b
(
5
)
F
i
b
(
4
)
]
Base * T^3 = \begin{bmatrix} 1 & 1 \end{bmatrix} * \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix} ^ {3} = \begin{bmatrix} Fib(5) & Fib(4) \end{bmatrix}
Base∗T3=[11]∗[1110]3=[Fib(5)Fib(4)]
至此,当你求斐波那契数列的第n项时,对应的矩阵公式就是:
[
1
1
]
∗
[
1
1
1
0
]
n
−
2
=
[
F
i
b
(
n
)
F
i
b
(
n
−
1
)
]
\begin{bmatrix} 1 & 1 \end{bmatrix} * \begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix} ^ {n-2} = \begin{bmatrix} Fib(n) & Fib(n-1) \end{bmatrix}
[11]∗[1110]n−2=[Fib(n)Fib(n−1)]
所得矩阵得第一行第一列即为结果。
从整个求解过程来看,最重要的就是分析这一步,分析出了 T、Base矩阵,剩下的就是用矩阵快速幂求出
T
x
T^x
Tx。(该题x为n-2)
矩阵快速幂的主要代码:
typedef struct node{
ll m[3][3];
} M;
M e; // 单位矩阵
// 求a*b
M M_mul(M a, M b){
M c;
for (int i = 1; i <= 2; ++i){
for (int j = 1; j <= 2; ++j){
c.m[i][j] = 0;
for (int k = 1; k <= 2; ++k){
c.m[i][j] = (c.m[i][j] + a.m[i][k]*b.m[k][j]) % MOD;
}
}
}
return c;
}
// 求a矩阵的times次方
M M_qpow(M a, ll times){
M res = e; // 先初始化为单位矩阵
while (times){
if (times & 1) res = M_mul(res, a); // 矩阵乘法
a = M_mul(a, a);
times >>= 1;
}
return res;
}
洛谷例题: