夜深人静写算法(二十)- 矩阵快速幂

一、引例

【例题一】 f ( 0 ) = 0 , f ( 1 ) = 1 , f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(0) = 0, f(1) = 1, f(n) = f(n − 1) + f(n − 2) f(0)=0,f(1)=1,f(n)=f(n1)+f(n2) 其中 ( n ≥ 2 ) (n ≥ 2) (n2),求 f ( n ) m o d    M ( M < = 1 0 9 ) f(n) \mod M (M<=10^9) f(n)modM(M<=109)

  • 这个数列就是经典的斐波那契数列,读者可以先想一下,如何在时间允许的情况下计算出 f ( n ) f(n) f(n) 的值;
  • 这节内容非常有意思,由于涉及到一个线性代数里面的结构,它的名字叫 矩阵,如果对大学的内容已经忘得一干二净的话,我们先来复习一些概念,为了避免过程枯燥乏味,所有定义相关的内容,我都会一笔带过,争取尽快达到读者想要观看的内容;

二、矩阵乘法

  • 矩阵 A x × y A_{x \times y} Ax×y 和 矩阵 B u × v B_{u \times v} Bu×v 相乘的前提条件是 y = = u y==u y==u ,并且相乘后得到的矩阵为 C x × v C_{x \times v} Cx×v(即 A A A 的行和 B B B 的列构成了矩阵 C C C 的行列);
  • 例如 2 × 3 2 \times 3 2×3 的矩阵 A 2 × 3 A_{2 \times 3} A2×3 3 × 4 3 \times 4 3×4 的矩阵 B 3 × 2 B_{3 \times 2} B3×2 相乘后得到一个 2 × 2 2 \times 2 2×2 的矩阵 C 2 × 2 C_{2 \times 2} C2×2 (用 A A A 的每一行去乘上 B B B 的每一列);
    A 2 × 3 = [ a 11 a 12 a 13 a 21 a 22 a 23 ] B 3 × 2 = [ b 11 b 12 b 21 b 22 b 31 b 32 ] A_{2 \times 3} = \left[ \begin{matrix} a_{11} & a_{12} & a_{13}\\ a_{21} & a_{22} & a_{23} \end{matrix} \right] \quad B_{3 \times 2} = \left[ \begin{matrix} b_{11} & b_{12}\\ b_{21} & b_{22}\\ b_{31} & b_{32} \end{matrix} \right] A2×3=[a11a21a12a22a13a23]B3×2=b11b21b31b12b22b32

C 2 × 2 = [ a 11 b 11 + a 12 b 21 + a 13 b 31 a 11 b 12 + a 12 b 22 + a 13 b 32 a 21 b 11 + a 22 b 21 + a 23 b 31 a 21 b 12 + a 22 b 22 + a 23 b 32 ] C_{2 \times 2} = \left[ \begin{matrix} a_{11}b_{11} + a_{12}b_{21} + a_{13}b_{31} & a_{11}b_{12} + a_{12}b_{22} + a_{13}b_{32} \\ a_{21}b_{11} + a_{22}b_{21} + a_{23}b_{31} & a_{21}b_{12} + a_{22}b_{22} + a_{23}b_{32} \\ \end{matrix} \right] \quad C2×2=[a11b11+a12b21+a13b31a21b11+a22b21+a23b31a11b12+a12b22+a13b32a21b12+a22b22+a23b32]

三、矩阵的幂

1、方阵

  • 行数 和 列数 相同的矩阵被称为方阵;
  • A m × m A_{m \times m} Am×m 被称为 m m m 阶方阵;
  • 两个方阵相乘的时间复杂度为 O ( m 3 ) O(m^3) O(m3)

2、矩阵的幂运算

  • 只有方阵才能进行幂运算,矩阵幂运算的定义为连续 n n n 个矩阵 A A A 连乘,表示为 A n A^n An
  • 矩阵连乘满足递推公式(其中 I I I 为单位矩阵 ):
    A n { I n = 0 A n − 1 × A n > 0 A^n\begin{cases} I & n=0\\ A^{n-1} \times A & n>0 \end{cases} An{ IAn1×An=0n>0
  • 若矩阵 A A A m m m 阶 方阵,那么这个算法的时间复杂度就是 O ( n m 3 ) O(nm^3) O(nm3)

四、矩阵快速幂

【例题二】 给定一个 m ( m < = 50 ) m (m<=50) m(m<=50) 阶矩阵,求它的 n ( n < = 1 0 9 ) n (n<=10^9) n(n<=109) 次幂的对角线和 m o d    1000007 \mod 1000007 mod1000007 的值;
A n = [ a 11 a 12 ⋯ a 1 m a 21 a 22 ⋯ a 2 m ⋮ ⋮ ⋱ ⋮ a m 1 a m 2 ⋯ a m m ] n A^n=\begin{bmatrix} {a_{11}}&{a_{12}}&{\cdots}&{a_{1m}}\\ {a_{21}}&{a_{22}}&{\cdots}&{a_{2m}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {a_{m1}}&{a_{m2}}&{\cdots}&{a_{mm}}\\ \end{bmatrix}^n An=a11a21am1a12a22am2a1ma2mammn

  • 核心还是求矩阵的 n n n 次幂,如果采用简单的连乘来求解,这个时间复杂度是完全无法接受的,我们联想到之前提到的整数的二分快速幂(整数快速幂),对于矩阵也是同样适用的;
    A n = { I n = 0 ( A n − 1 2 ) 2 × A n 为 奇 数 ( A n 2 ) 2 n 为 非 零 偶 数 A^{n} = \begin{cases} I & n = 0\\ (A^{\frac{n-1}{2}})^2 \times A& n 为奇数\\ (A^{\frac{n}{2}})^2 & n 为非零偶数 \end{cases} An=I(A2n1)2×A(A2n)2n=0nn
  • 再加上模加、模乘的性质,矩阵同样满足模幂运算,即:
    A n m o d    M = { I m o d    M n = 0 ( A n − 1 2 ) 2 × A m o d    M n 为 奇 数 ( A n 2 ) 2 m o d    M n 为 非 零 偶 数 A^{n} \mod M = \begin{cases} I \mod M & n = 0\\ (A^{\frac{n-1}{2}})^2 \times A \mod M & n 为奇数\\ (A^{\frac{n}{2}})^2 \mod M & n 为非零偶数 \end{cases} AnmodM=ImodM(A2n1)2×AmodM(A2n)2modMn=0nn
  • 如此一来,对于 m m m 阶方阵 A A A,时间复杂度就可以降到 O ( m 3 l o g n ) O(m^3log_n) O(m3logn)
  • 模板 C++ 代码:矩阵二分快速幂

五、矩阵快速幂的应用

1、线性递推

1)斐波那契数列

  • 还是回到本文开头的那个问题,如何计算斐波那契数列第 n n n 项模上 M M M
  • 相信聪明的读者已经想到了,我们今天的主角是:矩阵
  • 我们首先来看递推公式:
    f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n-1) + f(n-2) f(n)=f(n1)+f(n2)
  • 然后我们联想到:1 个 2 × 2 2 \times 2 2×2 的矩阵和 1 个 2 × 1 2 \times 1 2×1 的矩阵相乘,得到的还是一个 2 × 1 2 \times 1 2×1 的矩阵 (鬼才能联想到这个啊!!!第一个想出用矩阵的人真 TM 是鬼才!原来 ‘鬼才’ 是这么来的!!!);
  • 首先,利用递推公式填充 列向量 和 矩阵 :
    [ f ( n ) ? ] = [ 1 1 ? ? ] [ f ( n − 1 ) f ( n − 2 ) ] \left[ \begin{matrix} f(n) \\ ? \end{matrix} \right] = \left[ \begin{matrix} 1 & 1 \\ ? & ?\end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2)\end{matrix} \right] [f(n)?]=[1?1?][f(n1)f(n2)]
  • 接下来利用列向量的传递性把带有问号的列向量补全,得到:
    [ f ( n ) f ( n − 1 ) ] = [ 1 1 ? ? ] [ f ( n − 1 ) f ( n − 2 ) ] \left[ \begin{matrix} f(n) \\ f(n-1)\end{matrix} \right] = \left[ \begin{matrix} 1 & 1 \\ ? & ?\end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2)\end{matrix} \right] [f(n)f(n1)]=[1?1?][f(n1)f(n2)]
  • 再把带有问号的系数矩阵补全,得到:
    [ f ( n ) f ( n − 1 ) ] = [ 1 1 1 0 ] [ f ( n − 1 ) f ( n − 2 ) ] \left[ \begin{matrix} f(n) \\ f(n-1)\end{matrix} \right] = \left[ \begin{matrix} 1 & 1 \\ 1 & 0\end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2)\end{matrix} \right] [f(n)f(n1)]=[1110][f(n1)f(n2)]
  • 然后进行逐步化简,得到:
    [ f ( n ) f ( n − 1 ) ] = [ 1 1 1 0 ] [ f ( n − 1 ) f ( n − 2 ) ] = [ 1 1 1 0 ] [ 1 1 1 0 ] [ f ( n − 2 ) f ( n − 3 ) ] = [ 1 1 1 0 ] ⋯ [ 1 1 1 0 ] ⏟ n − 1 [ f ( 1 ) f ( 0 ) ] \begin{aligned} \left[ \begin{matrix} f(n) \\ f(n-1)\end{matrix} \right] &= \left[ \begin{matrix} 1 & 1 \\ 1 & 0\end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2)\end{matrix} \right] \\ &= \left[ \begin{matrix} 1 & 1 \\ 1 & 0\end{matrix} \right] \left[ \begin{matrix} 1 & 1 \\ 1 & 0\end{matrix} \right] \left[ \begin{matrix} f(n-2) \\ f(n-3)\end{matrix} \right] \\ &=\underbrace{ \left[ \begin{matrix} 1 & 1 \\ 1 & 0\end{matrix} \right] {\cdots}\left[ \begin{matrix} 1 & 1 \\ 1 & 0\end{matrix} \right] }_{n-1} \left[ \begin{matrix} f(1) \\ f(0)\end{matrix} \right] \\ \end{aligned} [f(n)f(n1)]=[1110][f(n1)f(n2)]=[1110][1110][f(n2)f(n3)]=n1 [1110][1110][f(1)f(0)]
  • 最后,根据矩阵乘法结合律,把前面的矩阵合并,得到:
    [ f ( n ) f ( n − 1 ) ] = [ 1 1 1 0 ] n − 1 [ f ( 1 ) f ( 0 ) ] = A n − 1 [ 1 0 ] \begin{aligned} \left[ \begin{matrix} f(n) \\ f(n-1)\end{matrix} \right] &=\left[ \begin{matrix} 1 & 1 \\ 1 & 0\end{matrix} \right]^{n-1}\left[ \begin{matrix} f(1) \\ f(0)\end{matrix} \right] \\ &=A^{n-1}\left[ \begin{matrix} 1 \\ 0 \end{matrix} \right] \end{aligned} [f(n)f(n1)]=[1110]n1[f(1)f(0)]=An1[10]
  • 那么对于 【例题一】,只要利用矩阵二分快速幂求得 A n − 1 m o d    M A^{n-1} \mod M An1modM ,再乘上初始列向量 [ 1 0 ] \left[ \begin{matrix} 1 \\ 0 \end{matrix} \right] [10],得到的列向量的第一个元素就是问题的解了;

2)乘法系数

【例题三】 f ( 0 ) = 0 , f ( 1 ) = 1 , f ( n ) = a f ( n − 1 ) + b f ( n − 2 ) f(0) = 0, f(1) = 1, f(n) = af(n − 1) + bf(n − 2) f(0)=0,f(1)=1,f(n)=af(n1)+bf(n2) 其中 ( n ≥ 2 ) (n ≥ 2) (n2),求 f ( n ) m o d    M ( M < = 1 0 9 ) f(n) \mod M (M<=10^9) f(n)modM(M<=109)

  • 这个问题当 a = b = 1 a = b = 1 a=b=1 的时候就是斐波那契数列了,参照斐波那契数列的矩阵,可以构造如下系数矩阵:
    [ a b 1 0 ] \left[ \begin{matrix} a & b \\ 1 & 0\end{matrix} \right] [a1b0]
  • 然后就是求二分快速幂的问题了,并且可以将情况推广到递推项更多的情况,当前项依赖前多少项的值,就构造多少阶的矩阵;对于递推式只和前几项有关,并且带有乘法系数的,可以参考如下构造方式:

构造方法

  • 1)构造一个 k k k 阶零方阵 ( k k k 代表当前项和前面多少项有关);
  • 2)第一行填递推系数;
  • 3)左下角放置一个 k − 1 k-1 k1 阶单位矩阵;
递推公式 系数矩阵
f ( n ) = a 0 f ( n − 1 ) f(n) = a_0f(n − 1) f(n)=a0f(n1) [ a 0 ] \left[ \begin{matrix} a_0 \end{matrix} \right] [a0]
f ( n ) = a 0 f ( n − 1 ) + a 1 f ( n − 2 ) f(n) = a_0f(n − 1) + a_1f(n-2) f(n)=a0f(n1)+a1f(n2) [ a 0 a 1 1 0 ] \left[ \begin{matrix} a_0 & a_1 \\ 1 & 0 \end{matrix} \right] [a01a10]
f ( n ) = a 0 f ( n − 1 ) + a 1 f ( n − 2 ) + a 2 f ( n − 3 ) f(n) = a_0f(n − 1) + a_1f(n-2) + a_2f(n-3) f(n)=a0f(n1)+a1f(n2)+a2f(n3) [ a 0 a 1 a 2 1 0 0 0 1 0 ] \left[ \begin{matrix} a_0 & a_1 & a_2 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{matrix} \right] a010a101a200
f ( n ) = a 0 f ( n − 1 ) + a 1 f ( n − 2 ) + a 2 f ( n − 3 ) + a 3 f ( n − 4 ) f(n) = a_0f(n − 1) + a_1f(n-2) + a_2f(n-3) + a_3f(n-4) f(n)=a0f(n1)+a1f(n2)+a2f(n3)+a3f(n4) [ a 0 a 1 a 2 a 3 1 0 0 0 0 1 0 0 0 0 1 0 ] \left[ \begin{matrix} a_0 & a_1 & a_2 & a_3 \\ 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \end{matrix} \right] a0100a1010a2001a3000

3)加法系数

【例题四】 已知公式: f ( n ) = { 1 ( n = 1 ) 2 ( n = 2 ) f ( n − 1 ) + 2 f ( n − 2 ) + n 3 ( n > 2 ) f(n) = \begin{cases} 1 & (n = 1) \\ 2 & (n = 2) \\ f(n-1) + 2f(n-2) + n^3 & (n > 2) \end{cases} f(n)=12f(n1)+2f(n2)+n3(n=1)(n=2)(n>2)

  • 给出 n n n,求 f ( n ) % 123456789 f(n) \% 123456789 f(n)%123456789

  • 这里的 n 3 n^3 n3 是递推公式的加法系数,沿用之前的方法,构造系数矩阵如下:
    [ f ( n ) f ( n − 1 ) ] = [ ? ? ? ? ] [ f ( n − 1 ) f ( n − 2 ) ] \left[ \begin{matrix} f(n) \\ f(n-1)\end{matrix} \right] = \left[ \begin{matrix} ? & ? \\ ? & ?\end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2)\end{matrix} \right] [f(n)f(n1)]=[????][f(n1)f(n2)]

  • 这时我们发现无法构造这个矩阵,因为多了一个加法系数,于是将列向量补齐,得到如下:
    [ f ( n ) f ( n − 1 ) n 3 ] = [ ? ? ? ? ? ? ? ? ? ] [ f ( n − 1 ) f ( n − 2 ) ( n − 1 ) 3 ] \left[ \begin{matrix} f(n) \\ f(n-1) \\ n^3 \end{matrix} \right] = \left[ \begin{matrix} ? & ? & ? \\ ? & ? & ? \\ ? & ? & ? \end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2) \\ (n-1)^3 \end{matrix} \right] f(n)f(n1)n3=?????????f(n1)f(n2)(n1)3

  • ( n − 1 ) 3 (n-1)^3 (n1)3 展开后发现还有 n 2 、 n n^2、n n2n 以及常数项,这些项无法互相抵消,所以都需要加到列向量中,于是就有了:
    [ f ( n ) f ( n − 1 ) n 3 n 2 n 1 ] = [ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ] [ f ( n − 1 ) f ( n − 2 ) ( n − 1 ) 3 ( n − 1 ) 2 ( n − 1 ) 1 ] \left[ \begin{matrix} f(n) \\f(n-1)\\ n^3 \\n^2\\n\\1 \end{matrix} \right]= \left[ \begin{matrix} ? & ? & ? & ? &? & ? \\ ? & ? & ? & ? &? & ? \\ ? & ? & ? & ? &? & ? \\ ? & ? & ? & ? &? & ? \\ ? & ? & ? & ? &? & ? \\? & ? & ? & ? &? & ? \end{matrix} \right] \left[ \begin{matrix} f(n-1) \\ f(n-2) \\ (n-1)^3 \\ (n-1)^2 \\ (n-1) \\ 1 \end{matrix} \right] f(n)f(n1)n3n2n1=????????????????????????????????????f(n1)f(n2)(n1)3(n1)2(n1)1

  • 根据递推公式构造出系数矩阵后二分求解:
    [ 1 2 1 3 3 1 1 0 0 0 0 0 0 0 1 3 3 1 0 0 0 1 2 1 0 0 0 0 1 1 0 0 0 0 0 1 ] \left[ \begin{matrix} 1 & 2 & 1 & 3 & 3 & 1 \\ 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 3 & 3 & 1\\0 & 0 & 0 &1 & 2 & 1 \\ 0 & 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 &0 & 0 & 1\end{matrix} \right] 110000200000101000303100303210101111

2、数列前缀和

  • 数列前缀和就是给定一个数列 f ( i ) f(i) f(i) 和一个次幂 k k k,求:
    S ( i ) = ∑ i = 1 N f ( i ) k S(i) = \sum_{i=1}^{N}f(i)^k S(i)=i=1Nf(i)k

1)一次幂前缀和

【例题五】 T [ 0 ] = T [ 1 ] = T [ 2 ] = 1 T[0] = T[1] = T[2] = 1 T[0]=T[1]=T[2]=1 T [ n ] = T [ n − 1 ] + T [ n − 2 ] + T [ n − 3 ] ( n > = 3 ) T[n] = T[n - 1] + T[n - 2] + T[n - 3] (n >= 3) T[n]=T[n1]+T[n2]+T[n3](n>=3)

  • 给定 a 和 b 求 ( T [ a ] + T [ a + 1 ] + . . . + T [ b ] ) % 1 , 000 , 000 , 007 (T[a] + T[a + 1] + ... + T[b]) \% 1,000,000,007 (T[a]+T[a+1]+...+T[b])%1,000,000,007
  • 首先,对于求部分和的问题,我们可以转化成前缀和,即:
  • S [ n ] = ∑ i = 0 n T [ i ] S[n] = \sum_{i=0}^n{T[i]} S[n]=i=0nT[i],则 ( T [ a ] + T [ a + 1 ] + . . . + T [ b ] ) = S [ b ] − S [ a − 1 ] (T[a] + T[a + 1] + ... + T[b]) = S[b] - S[a-1] (T[a]+T[a+1]+...+T[b])=S[b]S[a1],于是问题转化成求 S [ n ] S[n] S[n] 的问题;
  • 首先,我们根据递推公式得到:
    S [ n ] = ∑ i = 0 n T [ i ] = S [ n − 1 ] + T [ n ] = S [ n − 1 ] + T [ n − 1 ] + T [ n − 2 ] + T [ n − 3 ] \begin{aligned} S[n] &= \sum_{i=0}^n{T[i]} \\ &= S[n-1] + T[n]\\ &= S[n-1] + T[n - 1] + T[n - 2] + T[n - 3] \end{aligned} S[n]=i=0nT[i]=S[n1]+T[n]=S[n1]+T[n1]+T[n2]+T[n3]
  • 于是,我们可以构造如下系数矩阵,并且把上述的递推公式填充到矩阵系数和列向量中:
    [ S [ n ] ? ? ? ] = [ 1 1 1 1 ? ? ? ? ? ? ? ? ? ? ? ? ] [ S [ n − 1 ] T [ n − 1 ] T [ n − 2 ] T [ n − 3 ] ] \begin{aligned} \left[ \begin{matrix} S[n] \\ ? \\ ? \\ ? \end{matrix}\right] &= \left[ \begin{matrix} 1 & 1 & 1 & 1 \\ ? & ? & ? & ? \\ ? & ? & ? & ? \\ ? & ? & ? & ? \end{matrix}\right] \left[ \begin{matrix} S[n-1] \\ T[n-1] \\ T[n-2] \\ T[n-3] \end{matrix}\right] \end{aligned} S[n]???=1???1???1???1???S[n1]T[n1]T[n2]T[n3]
  • 接着,利用列向量传递性把参数补全,再利用递推公式补全系数矩阵,如下:
    [ S [ n ] T [ n ] T [ n − 1 ] T [ n − 2 ] ] = [ 1 1 1 1 0 1 1 1 0 1 0 0 0 0 1 0 ] [ S [ n − 1 ] T [ n − 1 ] T [ n − 2 ] T [ n − 3 ] ] \begin{aligned} \left[ \begin{matrix} S[n] \\ T[n] \\ T[n-1] \\ T[n-2] \end{matrix}\right] &= \left[ \begin{matrix} 1 & 1 & 1 & 1 \\ 0 & 1 & 1 & 1 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \end{matrix}\right] \left[ \begin{matrix} S[n-1] \\ T[n-1] \\ T[n-2] \\ T[n-3] \end{matrix}\right] \end{aligned} S[n]T[n]T[n1]T[n2]=1000111011011100S[n1]T[n1]T[n2]T[n3]

2)二次幂前缀和

【例题六】

  • A ( 0 ) = 1 , A ( 1 ) = 1 A(0) = 1 , A(1) = 1 A(0)=1,A(1)=1 A ( n ) = X ∗ A ( n − 1 ) + Y ∗ A ( n − 2 ) ( n > = 2 ) A(n) = X * A(n - 1) + Y * A(n - 2) (n >= 2) A(n)=XA(n1)+YA(n2)(n>=2) S ( n ) = ∑ i = 0 n A ( i ) 2 S(n) = \sum_{i=0}^{n}A(i)^2 S(n)=i=0nA(i)2
  • 首先利用递推式,可以得出 A ( n ) 2 A(n)^2 A(n)2 的递推式如下:
    A ( n ) 2 = ( X ∗ A ( n − 1 ) + Y ∗ A ( n − 2 ) ) 2 = X 2 A ( n − 1 ) 2 + 2 X Y A ( n − 1 ) A ( n − 2 ) + Y 2 A ( n − 2 ) 2 \begin{aligned} A(n)^2 &= (X * A(n - 1) + Y * A(n - 2))^2 \\ &= X^2 A(n - 1)^2 + 2XYA(n - 1)A(n - 2) + Y^2 A(n - 2)^2 \end{aligned} A(n)2=(XA(n1)+YA(n2))2=X2A(n1)2+2XYA(n1)A(n2)+Y2A(n2)2
  • S ( n ) S(n) S(n) 满足等式:
    S ( n ) = S ( n − 1 ) + A ( n ) 2 = S ( n − 1 ) + X 2 A ( n − 1 ) 2 + 2 X Y A ( n − 1 ) A ( n − 2 ) + Y 2 A ( n − 2 ) 2 \begin{aligned} S(n) &= S(n-1) + A(n)^2 \\ &= S(n-1) + X^2 A(n - 1)^2 + 2XYA(n - 1)A(n - 2) + Y^2 A(n - 2)^2 \end{aligned} S(n)=S(n1)+A(n)2=S(n1)+X2A(n1)2+2XYA(n1)A(n2)+Y2A(n2)2
  • 思路还是一样,首先根据递推公式构造列向量和系数矩阵:
    [ S ( n ) ? ? ? ] = [ 1 X 2 2 X Y Y 2 ? ? ? ? ? ? ? ? ? ? ? ? ] [ S ( n − 1 ) A ( n − 1 ) 2 A ( n − 1 ) A ( n − 2 ) A ( n − 2 ) 2 ] \begin{aligned} \left[ \begin{matrix} S(n) \\ ? \\ ? \\ ? \end{matrix}\right] &= \left[ \begin{matrix} 1 & X^2 & 2XY & Y^2 \\ ? & ? & ? & ? \\ ? & ? & ? & ? \\ ? & ? & ? & ? \end{matrix}\right] \left[ \begin{matrix} S(n-1) \\ A(n-1)^2 \\ A(n-1)A(n-2) \\ A(n-2)^2 \end{matrix}\right] \end{aligned} S(n)???=1???X2???2XY???Y2???S(n1)A(n1)2A(n1)A(n2)A(n2)2
  • 然后补充列向量,再根据列向量的递推关系得到完整的系数矩阵:
    [ S ( n ) A ( n ) 2 A ( n ) A ( n − 1 ) A ( n − 1 ) 2 ] = [ 1 X 2 2 X Y Y 2 0 X 2 2 X Y Y 2 0 X Y 0 0 1 0 0 ] [ S ( n − 1 ) A ( n − 1 ) 2 A ( n − 1 ) A ( n − 2 ) A ( n − 2 ) 2 ] = [ 1 X 2 2 X Y Y 2 0 X 2 2 X Y Y 2 0 X Y 0 0 1 0 0 ] n − 1 [ S ( 1 ) A ( 1 ) 2 A ( 1 ) A ( 0 ) A ( 0 ) 2 ] = A n − 1 [ 2 1 1 1 ] \begin{aligned} \left[ \begin{matrix} S(n) \\ A(n)^2 \\ A(n)A(n-1) \\ A(n-1)^2 \end{matrix}\right] &= \left[ \begin{matrix} 1 & X^2 & 2XY & Y^2 \\ 0 & X^2 & 2XY & Y^2 \\ 0 & X & Y & 0 \\ 0 & 1 & 0 & 0 \end{matrix}\right] \left[ \begin{matrix} S(n-1) \\ A(n-1)^2 \\ A(n-1)A(n-2) \\ A(n-2)^2 \end{matrix}\right] \\ &=\left[ \begin{matrix} 1 & X^2 & 2XY & Y^2 \\ 0 & X^2 & 2XY & Y^2 \\ 0 & X & Y & 0 \\ 0 & 1 & 0 & 0 \end{matrix}\right]^{n-1} \left[ \begin{matrix} S(1) \\ A(1)^2 \\ A(1)A(0) \\ A(0)^2 \end{matrix}\right] \\ &= A^{n-1} \left[ \begin{matrix} 2 \\ 1 \\ 1 \\ 1\end{matrix}\right] \\ \end{aligned} S(n)A(n)2A(n)A(n1)A(n1)2=1000X2X2X12XY2XYY0Y2Y200S(n1)A(n1)2A(n1)A(n2)A(n2)2=1000X2X2X12XY2XYY0Y2Y200n1S(1)A(1)2A(1)A(0)A(0)2=An12111

3)K 次幂前缀和

【例题七】
F ( 1 ) = f 1 , F ( 2 ) = f 2 , F ( n ) = a F ( n − 1 ) + b F ( n − 2 ) F(1) = f_1, F(2) = f_2, F(n) = aF(n-1) + bF(n-2) F(1)=f1,F(2)=f2,F(n)=aF(n1)+bF(n2)

  • 给定 f 1 、 f 2 、 a 、 b 、 n , m , k ( k < = 50 ) f_1、f_2、a、b、n,m,k(k <= 50) f1f2abnmk(k<=50),求 ∑ i = 1 n F ( i ) k m o d    m \sum_{i=1}^n F(i)^k \mod m i=1nF(i)kmodm
  • 这个问题就留给聪明的读者吧 ^ _ ^【先想一下,实在想不出来就去看讲解吧:传送门】

3、矩阵 K 次幂前缀和

【例题八】 给出一个 n × n n × n n×n 的矩阵 A A A 和两个正整数 k , m k, m k,m, 求 S ( k ) = ( A + A 2 + A 3 + … + A k ) m o d    m S(k) = (A + A^2 + A^3 + … + A^k) \mod m S(k)=(A+A2+A3++Ak)modm

  • 难度:★★☆☆☆
  • 题解:首先,如果 k k k 为偶数,则 S ( k ) S(k) S(k) 满足如下递推式:
    S ( k ) = ( A + A 2 + A 3 + … + A k ) = A ∗ S ( k − 1 ) + A \begin{aligned} S(k) &= (A + A^2 + A^3 + … + A^k) \\ &= A * S(k-1) + A \end{aligned} S(k)=(A+A2+A3++Ak)=AS(k1)+A
  • 根据递推式,生成系数矩阵,这里的系数又是一个矩阵:
    [ S ( k ) ? ] = [ A A ? ? ] [ S ( k − 1 ) I ] \left[ \begin{matrix} S(k) \\ ? \end{matrix} \right] = \left[ \begin{matrix} A & A \\ ? & ?\end{matrix} \right] \left[ \begin{matrix} S({k-1}) \\ I \end{matrix} \right] [S(k)?]=[A?A?][S(k1)I]
  • 最后,填充 ?项,构造的矩阵如下( A A A 为原矩阵, O O O 为零矩阵, I I I 为单位矩阵):
    [ S ( k ) I ] = [ A A O I ] [ S ( k − 1 ) I ] = [ A A O I ] k − 1 [ S ( 1 ) I ] = B k − 1 [ A I ] \begin{aligned} \left[ \begin{matrix} S(k) \\ I \end{matrix} \right] &= \left[ \begin{matrix} A & A \\ O & I\end{matrix} \right]\left[ \begin{matrix} S(k-1) \\ I \end{matrix} \right] \\ &=\left[ \begin{matrix} A & A \\ O & I\end{matrix} \right]^{k-1}\left[ \begin{matrix} S(1) \\ I \end{matrix} \right] \\ &=B^{k-1}\left[ \begin{matrix} A \\ I \end{matrix} \right] \end{aligned} [S(k)I]=[AOAI][S(k1)I]=[AOAI]k1[S(1)I]=Bk1[AI]
  • 矩阵 B B B 的阶数为矩阵 A A A 的两倍,利用矩阵二分求解 B B B k − 1 k-1 k1 次幂后再乘上列向量,得到的列向量的上半部分就是所求的 S ( k ) S(k) S(k)

4、动态规划配合构造矩阵

1)路径数 - 转化成图

【例题九】 给定一个 n ( n < = 100 ) n (n<=100) n(n<=100) 个顶点的有向图,然后一串询问,求 a a a b b b 经过 k k k ( 0 < = a , b < n , k < = 1 0 9 ) (0<=a,b<n, k<=10^9) (0<=a,b<n,k<=109) 步的方案数;

  • f ( n , v ) f(n, v) f(n,v) 为从某个点出发,经过 n n n 步以后到达 v v v 的方案数,那么有状态转移如下:
    f ( n , v ) = { 1 n = 0 , v = a 0 n = 0 , v ≠ a ∑ u − > v f ( n − 1 , u ) n > 0 f(n,v) =\begin{cases} 1 & n = 0, v=a\\ 0 & n = 0, v \not= a\\ \sum_{}^{u->v}f(n-1,u) & n > 0 \end{cases} f(n,v)=10u>vf(n1,u)n=0,v=an=0,v=an>0
  • 举个例子,有向图如下:
0
1
2
  • 这个图的邻接矩阵如下( A [ u ] [ v ] 表 示 u 到 v 有 多 少 条 边 A[u][v] 表示 u 到 v 有多少条边 A[u][v]uv):
    A = [ 0 1 2 1 0 0 0 0 0 ] A = \left[ \begin{matrix} 0 & 1 & 2\\ 1 & 0 & 0 \\ 0 & 0 & 0 \end{matrix} \right] A=010100200
  • 根据状态转移构造出如下矩阵递推关系:
    [ f ( n , 0 ) f ( n , 1 ) f ( n , 2 ) ] = [ 0 1 0 1 0 0 2 0 0 ] [ f ( n − 1 , 0 ) f ( n − 1 , 1 ) f ( n − 1 , 2 ) ] \left[ \begin{matrix} f(n,0)\\ f(n,1) \\ f(n,2) \end{matrix} \right] = \left[ \begin{matrix} 0 & 1 & 0\\ 1 & 0 & 0 \\ 2 & 0 & 0 \end{matrix} \right] \left[ \begin{matrix} f(n-1,0)\\ f(n-1,1) \\ f(n-1,2) \end{matrix} \right]\\ f(n,0)f(n,1)f(n,2)=012100000f(n1,0)f(n1,1)f(n1,2)
  • 观察发现系数矩阵和正好是邻接矩阵的转置,于是根据邻接矩阵建立反图,再用 k k k 次幂二分求解,最后乘上一个列向量,列向量第 a a a 行为 1 1 1,其他都为 0 0 0,得到的列向量的第 b b b 行就是所求的 a a a b b b 经过 k k k 步 的方案数;

2)数位动态规划

【例题十】 一个由 1 1 1 0 0 0 组成的字符串,任何子串都不能包含 101 和 111 101 和 111 101111,求这样的长度为 L ( L < = 1 0 6 ) L (L <= 10^6) L(L<=106) 的字符串的种数;

  • f ( n , x ) f(n, x) f(n,x) 表示长度为 n n n,最后三位为 x x x 的合法字符串方案数;
  • 例如 f ( 35 , 100 ) f(35, 100) f(35,100) 代表长度为 35,最后三位为 110 的方案数,那么有状态转移方程:
    f ( 35 , 100 ) = f ( 34 , 010 ) + f ( 34 , 110 ) f(35, 100) = f(34, 010) + f(34, 110) f(35,100)=f(34,010)+f(34,110)
100
110
010
  • 三位的 ‘01’ 串总共 8 8 8 种情况,去掉两种不合法的状态,其他状态的状态转移图如下:
100
101
110
111
001
011
  • 通过邻接矩阵构造出转置矩阵作为系数矩阵,求转换成了从 a a a 点到 b b b 点经过 k k k 步的路径数问题了;

5、双变量交换递推

【例题十一】

  • 给定 n ( n < = 1 0 9 ) n(n <= 10^9) n(n<=109),求 ⌊ ( 2 + 3 ) 2 n ⌋ m o d    1024 \lfloor (\sqrt 2 + \sqrt 3)^{2n} \rfloor \mod 1024 (2 +3 )2nmod1024
  • 首先,令 f ( n ) = ( 2 + 3 ) 2 n = ( 5 + 2 6 ) n f(n) = {(\sqrt{2}+\sqrt{3})}^{2n} = (5+2\sqrt{6})^n f(n)=(2 +3 )2n=(5+26 )n,无论 n 多大,一定可以表示成 f ( n ) = A n + B n 6 f(n) = A_n + B_n\sqrt{6} f(n)=An+Bn6 ,则有如下递推式:
    f ( n ) = A n + B n 6 = ( A n − 1 + B n − 1 6 ) ( 5 + 2 6 ) = ( 5 A n − 1 + 12 B n − 1 ) + ( 2 A n − 1 + 5 B n − 1 ) 6 \begin{aligned} f(n) &= A_n + B_n\sqrt{6} \\ &= (A_{n-1} + B_{n-1}\sqrt{6})(5+2\sqrt{6})\\ &= (5A_{n-1} + 12B_{n-1}) + (2A_{n-1} + 5B_{n-1})\sqrt{6} \end{aligned} f(n)=An+Bn6 =(An1+Bn16 )(5+26 )=(5An1+12Bn1)+(2An1+5Bn1)6
  • 表示成矩阵的形式如下:
    [ A n B n ] = [ 5 12 2 5 ] [ A n − 1 B n − 1 ] = [ 5 12 2 5 ] n − 1 [ 5 2 ] \left[ \begin{matrix} A_n \\B_n\end{matrix} \right]= \left[ \begin{matrix} 5 & 12\\ 2 & 5\end{matrix} \right] \left[ \begin{matrix} A_{n-1} \\B_{n-1} \end{matrix} \right]= \left[ \begin{matrix} 5 & 12\\ 2 & 5\end{matrix} \right]^{n-1} \left[ \begin{matrix} 5 \\2 \end{matrix} \right] [AnBn]=[52125][An1Bn1]=[52125]n1[52]
    又由于 ( 5 + 2 6 ) ( 5 − 2 6 ) = 1 (5+2\sqrt{6})(5-2\sqrt{6})=1 (5+26 )(526 )=1,得到 ( 5 + 2 6 ) n ( 5 − 2 6 ) n = 1 (5+2\sqrt{6})^n(5-2\sqrt{6})^n=1 (5+26 )n(526 )n=1,则 ( A n + B n 6 ) ( A n − B n 6 ) = 1 (A_n+B_n\sqrt{6})(A_n-B_n\sqrt{6})=1 (An+Bn6 )(AnBn6 )=1,得到:
    6 B n 2 = A n 2 − 1 6B_n^2 = A_n^2 - 1 6Bn2=An21,从而推导出 B n 6 = A n 2 − 1 B_n\sqrt{6} = \sqrt{A_n^2 - 1} Bn6 =An21 ,于是 B n 6 B_n\sqrt{6} Bn6 的整数部分就是 A n − 1 A_n-1 An1,所以我们要求的答案就是 ( 2 A n − 1 ) % 1024 (2A_n-1) \% 1024 (2An1)%1024,矩阵求解 A n A_n An

6、扩展欧拉定理配合降幂

【例题十二】 F ( 0 ) = a , F ( 1 ) = b , F ( n ) = F ( n − 1 ) ∗ F ( n − 2 ) ( n > 1 ) , 给 定 a 、 b 、 n ( n < = 1 0 9 ) , 求 F ( n ) m o d    1000000007 F(0) = a, F(1) = b, F(n) = F(n-1) * F(n-2) ( n > 1 ),给定 a、b、n(n <=10^9),求 F(n) \mod 1000000007 F(0)=a,F(1)=b,F(n)=F(n1)F(n2)(n>1)abn(n<=109)F(n)mod1000000007

  • 根据递推公式容易得到 F ( n ) = a f ( n − 2 ) b f ( n − 1 ) F(n) = a^{f(n-2)}b^{f(n-1)} F(n)=af(n2)bf(n1),其中 f ( 0 ) = f ( 1 ) = 1 f(0)=f(1)=1 f(0)=f(1)=1,且满足 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n-1) + f(n-2) f(n)=f(n1)+f(n2),即斐波那契数列;

  • G ( n , k ) = k f ( n ) m o d    1000000007 G(n, k) = k^{f(n)} \mod1000000007 G(n,k)=kf(n)mod1000000007,那么我们只需要求出 G ( n , k ) G(n, k) G(n,k) 就可以求得原式的解;

  • 扩展欧拉定理
    a b m o d    c = { a b m o d    φ ( c ) m o d    c g c d ( a , c ) = 1 a b m o d    c g c d ( a , c ) ≠ 1 , b < φ ( c ) a b m o d    φ ( c ) + φ ( c ) m o d    c g c d ( a , c ) ≠ 1 , b > = φ ( c ) a^{b} \mod c = \begin {cases} a^{b \mod \varphi(c)} \mod c & { gcd(a,c)=1} \\ a^{b} \mod c & { gcd(a,c) \neq 1 ,b < \varphi(c)} \\ a^{b \mod \varphi(c) + \varphi(c)} \mod c & { gcd(a,c) \neq 1 ,b >= \varphi(c)} \\ \end {cases} abmodc=abmodφ(c)modcabmodcabmodφ(c)+φ(c)modcgcd(a,c)=1gcd(a,c)=1b<φ(c)gcd(a,c)=1b>=φ(c)

  • f ( n ) < φ ( 1000000007 ) f(n) < \varphi(1000000007) f(n)<φ(1000000007) 说明 n 比较小,直接求递推求出来即可;

  • f ( n ) > = φ ( 1000000007 ) f(n) >= \varphi(1000000007) f(n)>=φ(1000000007) 时,根据扩展欧拉定理,得到:
    G ( n , k ) = k f ( n ) m o d    1000000007 = k f ( n ) m o d    φ ( 1000000007 ) + φ ( 1000000007 ) m o d    1000000007 \begin{aligned} G(n, k) &= k^{f(n)} \mod1000000007 \\ &= k^{f(n) \mod \varphi(1000000007) + \varphi(1000000007)} \mod1000000007 \end{aligned} G(n,k)=kf(n)mod1000000007=kf(n)modφ(1000000007)+φ(1000000007)mod1000000007

  • f ( n ) f(n) f(n) 是最基本的斐波那契数列,直接用矩阵二分求解即可;

7、其他算法配合矩阵优化

1)循环节降幂

  • 对于矩阵 A A A,要求 A k m o d    M A^k \mod M AkmodM,如果 M M M 比较小,可以暴力计算出 A t m o d    M = I A^t \mod M = I AtmodM=I,这里的 t t t 就是矩阵循环节,然后就有:
    A k m o d    M = A ( k m o d    t ) m o d    M A^k \mod M = A^{(k \mod t)} \mod M AkmodM=A(kmodt)modM

2)AC自动机

  • 利用 AC 自动机 构造 trie 图,并且在 trie 图上进行矩阵二分;

3)搜索

  • 利用搜索 ( B F S / D F S ) (BFS / DFS) BFS/DFS 枚举所有状态转移的情况,然后进行矩阵二分;

六、矩阵快速幂题集整理

题目链接 难度 算法简介
HDU 1575 Tr A ★☆☆☆☆ 矩阵快速幂 - 模板题
POJ 3070 Fibonacci ★☆☆☆☆ 矩阵快速幂 - 线性递推 - 模板题
HDU 2157 How many ways?? ★☆☆☆☆ 矩阵乘法计算路径数 - 模板题
HDU 1757 A Simple Math Problem ★☆☆☆☆ 线性递推 - 模板题
POJ 2118 Firepersons ★☆☆☆☆ 线性递推
POJ 3233 Matrix Power Series ★★☆☆☆ 矩阵 K 次幂前缀和 - 模板题
HDU 5015 233 Matrix ★★☆☆☆ 线性递推
HDU 6470 Count ★★☆☆☆ 线性递推
HDU 4686 Arc of Dream ★★☆☆☆ 线性递推
HDU 2276 Kiki & Little Kiki 2 ★★☆☆☆ 位运算 + 矩阵快速幂
HDU 2604 Queue ★★☆☆☆ 简单动态规划 + 矩阵快速幂
Lucky Coins Sequence ★★☆☆☆ 简单动态规划 + 矩阵快速幂
POJ 3734 Blocks ★★☆☆☆ 简单动态规划 + 矩阵快速幂
HDU 2065 "红色病毒"问题 ★★☆☆☆ 简单动态规划 + 矩阵快速幂
HDU 2793 Sum of Tribonacci Numbers ★★☆☆☆ 矩阵快速幂求数列前缀和
Tower ★★☆☆☆ 矩阵快速幂求数列次幂前缀和
HDU 3306 Another kind of Fibonacci ★★☆☆☆ 矩阵快速幂求数列次幂前缀和
HDU 3096 Life Game ★★★☆☆ 动态规划 + 矩阵快速幂
HDU 2256 Problem of Precision ★★★☆☆ 双变量交换递推
HDU 3292 No more tricks, Mr Nanguo ★★★☆☆ 双变量交换递推
HDU 6030 Happy Necklace ★★★☆☆ 动态规划 + 矩阵快速幂
POJ 3735 Training little cats ★★★☆☆ 根据规则进行矩阵构造
HDU 5895 Mathematician QSC ★★★☆☆ 扩展欧拉定理 + 矩阵快速幂求数列次幂前缀和
HDU 4549 M斐波那契数列 ★★★☆☆ 扩展欧拉定理 + 矩阵快速幂
HDU 2254 奥运 ★★★☆☆ 哈希表 + 矩阵 K 次幂前缀和
HDU 1588 Gauss Fibonacci ★★★☆☆ 矩阵 K 次幂前缀和
HDU 3936 FIB Query ★★★☆☆ 矩阵 K 次幂前缀和
HDU 2294 Pendant ★★★☆☆ 动态规划 + 矩阵次幂前缀和
HDU 2238 机器人的舞蹈II ★★★☆☆ DFS + 矩阵快速幂
HDU 2842 Chinese Rings ★★★☆☆ BFS + 矩阵快速幂
HDU 5451 Best Solver ★★★☆☆ 矩阵循环节 + 双变量交换递推
HDU 3658 How many words ★★★☆☆ 容斥原理 + 矩阵快速幂
HDU 5607 graph ★★★☆☆ 逆元 + 矩阵求路径数
HDU 1977 Odd Loving Bakers ★★★★☆ 奇数的性质 + 矩阵快速幂
HDU 4291 A Short problem ★★★★☆ 矩阵循环节 + 矩阵快速幂
HDU 3483 A Very Simple Problem ★★★★☆ 二项式定理 + 矩阵前缀和
HDU 3509 Buge’s Fibonacci Number Problem ★★★★☆ 二项式定理 + 矩阵前缀和
HDU 2855 Fibonacci Check-up ★★★★☆ 二项式定理 + 矩阵前缀和
HDU 5986 Fibonacci ★★★★★ 矩阵循环节 + 矩阵快速幂
HDU 6755 Fibonacci Sum ★★★★★ 二次剩余 + 费马小定理 + 斐波那契数列通项公式 + 二分快速幂

猜你喜欢

转载自blog.csdn.net/WhereIsHeroFrom/article/details/109703377