蓝桥杯备赛--教你用矩阵优化递推

先导知识

  1. 矩阵乘法
    [ 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]
    由此可见矩阵乘法不满足交换律!
  2. 单位矩阵(矩阵对角线为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(n1)+Fib(n2)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(n1) F i b ( n − 2 ) Fib(n-2) Fib(n2) 决定的。
那么我们就可以构造一个状态转移矩阵 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(n1)Fib(n2)][11]
= F i b ( n − 1 ) + F i b ( n − 2 ) = Fib(n-1)+Fib(n-2) =Fib(n1)+Fib(n2)
= 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(n1),所以还需要求一下 F i b ( n − 1 ) Fib(n-1) Fib(n1)
[ 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(n1)Fib(n2)][10]
= F i b ( n − 1 ) = Fib(n-1) =Fib(n1)
所以这个 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} BaseT3=[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]n2=[Fib(n)Fib(n1)]
所得矩阵得第一行第一列即为结果。
从整个求解过程来看,最重要的就是分析这一步,分析出了 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;
}

洛谷例题:

  1. Chino的数列
  2. 斐波那契数列

你可能感兴趣的:(数据结构与算法,算法,acm竞赛,c++)