我是靠谱客的博主 飘逸老师,这篇文章主要介绍矩阵快速幂1.快速幂2.矩阵快速幂,现在分享给大家,希望可以做个参考。

1.快速幂

快速幂也叫二进制取幂,想要快速求出 a n a^n an的结果就用它来求。

a n a^n an表示将n个a乘在一起,时间复杂度是O(n) 级别,如果n太大的话这种方法就不适用了。

如果使用快速幂,时间复杂度能达到O( l o g 2 log_2 log2​n),因为n有⌊ l o g 2 log_2 log2​n⌋ + 1 个二进制位,所以当知道了每一位的值后,只需要通过 l o g 2 log_2 log2​n次乘法就可计算出 a n a^n an。

用快速幂进行计算
例如计算 a 9 a^9 a9,9的二进制是1001, 9 = 1 × 2 0 2^0 20 + 0 × 2 1 2^1 21 + 0 × 2 2 2^2 22 +1 × 2 3 2^3 23 = 2 1 2^1 21 + 2 3 2^3 23 ;
因此 a 9 a^9 a9 = a(2^1 + 2^3)= a2^1 * a2^3 , 也就是a1 * a8。现在这样就快多了吧,原来9个a连乘要计算8次乘法,现在使用快速幂只要乘两次。
但是像a8这种式子好像不是很好求的样子。。。

long long pow(int a, int b)
{
    long long int ans = 1;
    while(b)
    {
        if(b & 1) //判断b的二进制最后一位是不是1
        {
        	 ans *= a;
        }
        a *= a;  //累乘,以便对ans做出贡献
        b >>= 1; //b右移一位,去掉最后一位
    }
    return ans;
}

关于代码中累乘 a *= a
a *= a 即 a = a2,再下一步就是a2 * a2 = a4,再下一步就是a4 * a4 = a8… …
这样随着b右移,a也发生变化:a1 -> a2->a4->a8… … a的指数恰好是2x形式,再看a9 = a1 * a8,类似于 a8这样的式子就完美求出来了,当b二进制当前的末位为1的时候,只要把a乘给ans就能更新ans了。

2.矩阵快速幂

两个矩阵相乘
( a 11 a 12 . . . a 1 n a 21 a 22 . . . a 2 n a 31 a 32 . . . a 3 n ) ∗ ( b 11 b 12 . . . b 1 n b 21 b 22 . . . b 2 n b 31 b 32 . . . b 3 n ) = ( c 11 c 12 . . . c 1 n c 21 c 22 . . . c 2 n c 31 c 32 . . . c 3 n ) begin{pmatrix} a_{11} & a_{12}& ... & a_{1n} \ a_{21} & a_{22} & ... & a_{2n} \ a_{31} & a_{32} & ... & a_{3n} end{pmatrix} *begin{pmatrix} b_{11} & b_{12} & ... & b_{1n} \ b_{21} & b_{22} & ... & b_{2n} \ b_{31} & b_{32} & ... & b_{3n} end{pmatrix}=begin{pmatrix} c_{11} & c_{12}& ... & c_{1n} \ c_{21} & c_{22} & ... & c_{2n} \ c_{31} & c_{32} & ... & c_{3n} end{pmatrix} ⎝⎛​a11​a21​a31​​a12​a22​a32​​.........​a1n​a2n​a3n​​⎠⎞​∗⎝⎛​b11​b21​b31​​b12​b22​b32​​.........​b1n​b2n​b3n​​⎠⎞​=⎝⎛​c11​c21​c31​​c12​c22​c32​​.........​c1n​c2n​c3n​​⎠⎞​
举个例子
( a b c d ) ∗ ( a 1 b 1 c 1 d 1 ) = ( a ∗ a 1 + b ∗ c 1 a ∗ b 1 + b ∗ d 1 c ∗ a 1 + d ∗ c 1 c ∗ b 1 + d ∗ d 1 ) begin{pmatrix} a & b \ c & d end{pmatrix} * begin{pmatrix} a_1 & b_1 \ c_1 & d_1 end{pmatrix}=begin{pmatrix} a*a_1 +b*c_1 & a*b_1+b*d_1 \ c*a_1+d*c_1 & c*b_1+d*d_1 end{pmatrix} (ac​bd​)∗(a1​c1​​b1​d1​​)=(a∗a1​+b∗c1​c∗a1​+d∗c1​​a∗b1​+b∗d1​c∗b1​+d∗d1​​)

注意:
1.矩阵A*B必须满足 A的列数=B的行数

2.若矩阵A是一个m行s列的矩阵,矩阵B是一个s行n列的矩阵,则C=A*B是一个m行n列的矩阵

矩阵快速幂
设A为矩阵,求An,若直接相乘,需要连乘n-1次,时间复杂度为O(n),
使用矩阵快速幂,时间复杂度为O( l o g 2 n ) log_2n) log2​n)。

那么如何实现矩阵快速幂呢?只要快速幂中的乘法改成矩阵的乘法就行了。

const int N = 2;
int ans[N][N];
int temp[N][N];
int num[N][N];
void multi(int a[][N], int b[][N]) //两个矩阵相乘
{
    memset(temp, 0, sizeof(temp));
    for(int i = 0; i < N; i++)
        for(int j = 0; j < N; j++)
        for(int k = 0; k < N; k++)
        temp[i][j] = temp[i][j] + a[i][k] * b[k][j];

    for(int i = 0; i < N; i++)
        for(int j = 0; j < N; j++)
        a[i][j] = temp[i][j];
}
void MatPow(int a[][N], int n)  //计算矩阵a的n次方
{
    memset(res, 0, sizeof(res));
    for(int i = 0; i < N; i++) ans[i][i] = 1; //初始化为单位矩阵,相当于快速幂中的ans = 1

    while(n)
    {
        if(n&1)
        {
            multi(ans, a); //矩阵ans与矩阵a相乘
        }
        multi(a, a);//矩阵a自乘
        n >>= 1;
    }
}

矩阵快速幂主要是用来求一个复杂递推式的某一项问题,只要构造出了关系矩阵,问题就好解决了。

如何构造矩阵

首先说明一下,能用矩阵快速幂优化的递推类型是f[n]=2f[n-1]+3f[n-2]+n3+1这类的,也就是递推要是线性的,且f[n-i]的系数要是常数,可以含有n的多项式。

下面介绍一些递推式:
递推式1.斐波那契数列: F n = F n − 1 + F n − 2 , F 0 = 1 , F 1 = 2 , 求 F n F_n=F_{n-1}+F_{n-2},F_0=1, F_1=2,求F_n Fn​=Fn−1​+Fn−2​,F0​=1,F1​=2,求Fn​
设转换矩阵为A,那么
A ∗ ( F n − 2 F n − 1 ) = ( F n − 1 F n ) = ( F n − 1 F n − 1 + F n − 2 ) A* begin{pmatrix} F_{n-2} \ F_{n-1} end{pmatrix} = begin{pmatrix} F_{n-1} \ F_{n} end{pmatrix} =begin{pmatrix} F_{n-1} \ F_{n-1} +F_{n-2} end{pmatrix} A∗(Fn−2​Fn−1​​)=(Fn−1​Fn​​)=(Fn−1​Fn−1​+Fn−2​​)

之前说过,若矩阵a是一个m行s列的矩阵,矩阵b是一个s行n列的矩阵,则c=a*b是一个m行n列的矩阵


易知,A是一个2×2的矩阵。
设
A = ( a b c d ) A= begin{pmatrix} a & b \ c & d end{pmatrix} A=(ac​bd​)
那么
a ∗ F n − 2 + b ∗ F n − 1 = F n − 1 a * F_{n-2}+b*F_{n-1} = F_{n-1} a∗Fn−2​+b∗Fn−1​=Fn−1​,
c ∗ F n − 2 + d ∗ F n − 1 = F n − 1 + F n − 2 c * F_{n-2}+d*F_{n-1} = F_{n-1}+F_{n-2} c∗Fn−2​+d∗Fn−1​=Fn−1​+Fn−2​
得a=0,b=1,c=1,d=1
A = ( 0 1 1 1 ) A= begin{pmatrix} 0 & 1 \ 1 & 1 end{pmatrix} A=(01​11​)
这样就求出了转换矩阵A

A ∗ ( F 1 F 2 ) = ( F 2 F 3 ) A* begin{pmatrix} F_1 \ F_2 end{pmatrix} = begin{pmatrix} F_2 \ F_3 end{pmatrix} A∗(F1​F2​​)=(F2​F3​​)

A ∗ ( F 2 F 3 ) = ( F 3 F 4 ) A* begin{pmatrix} F_2 \ F_3 end{pmatrix} = begin{pmatrix} F_3 \ F_4 end{pmatrix} A∗(F2​F3​​)=(F3​F4​​)
A n − 1 ∗ ( F 1 F 2 ) = ( F n F n + 1 ) A^{n-1}* begin{pmatrix} F_1 \ F_2 end{pmatrix} = begin{pmatrix} F_n \ F_{n+1} end{pmatrix} An−1∗(F1​F2​​)=(Fn​Fn+1​​)

最后得到的矩阵的第一个元素即为 F n F_n Fn​
一些类似的数列:

(1) F n = F n − 1 + F n − 2 + 1 , F 1 = 1 , F 2 = 2 , 求 F n F_n = F_{n-1}+F_{n-2} + 1,F_1=1, F_2=2,求F_n Fn​=Fn−1​+Fn−2​+1,F1​=1,F2​=2,求Fn​

A ∗ ( F n − 2 F n − 1 1 ) = ( F n − 1 F n 1 ) = ( F n − 1 F n − 2 + F n − 1 + 1 1 ) A* begin{pmatrix} F_{n-2} \ F_{n-1} \ 1 end{pmatrix} = begin{pmatrix} F_{n-1} \ F_n\ 1 end{pmatrix}= begin{pmatrix} F_{n-1} \ F_{n-2}+F_{n-1} + 1 \ 1 end{pmatrix} A∗⎝⎛​Fn−2​Fn−1​1​⎠⎞​=⎝⎛​Fn−1​Fn​1​⎠⎞​=⎝⎛​Fn−1​Fn−2​+Fn−1​+11​⎠⎞​
解得 A = ( 0 1 0 1 1 0 0 1 1 ) A= begin{pmatrix} 0 & 1 & 0\ 1 & 1 & 0 \ 0 & 1 & 1 end{pmatrix} A=⎝⎛​010​111​001​⎠⎞​
求 F n F_n Fn​:
A n − 1 ∗ ( F 1 F 2 1 ) = ( F n F n + 1 1 ) A^{n-1}* begin{pmatrix} F_1 \ F_2 \ 1 end{pmatrix} = begin{pmatrix} F_n \ F_{n+1} \ 1 end{pmatrix} An−1∗⎝⎛​F1​F2​1​⎠⎞​=⎝⎛​Fn​Fn+1​1​⎠⎞​
最后得到的矩阵的第一个元素即为 F n F_n Fn​

(2) F n = F n − 1 + F n − 2 + n + 1 , F 0 = 1 , F 1 = 2 , 求 F n F_n = F_{n-1}+F_{n-2} + n + 1,F_0=1, F_1=2,求F_n Fn​=Fn−1​+Fn−2​+n+1,F0​=1,F1​=2,求Fn​

A ∗ ( F n − 2 F n − 1 n 1 ) = ( F n + 1 F n n + 1 1 ) = ( F n + 1 F n − 2 + F n − 1 + n + 1 n + 1 1 ) A* begin{pmatrix} F_{n-2} \ F_{n-1} \ n \ 1 end{pmatrix} = begin{pmatrix} F_{n+1} \ F_n \ n+1 \ 1 end{pmatrix} = begin{pmatrix} F_{n+1} \ F_{n-2}+F_{n-1}+n+1 \ n+1 \ 1 end{pmatrix} A∗⎝⎜⎜⎛​Fn−2​Fn−1​n1​⎠⎟⎟⎞​=⎝⎜⎜⎛​Fn+1​Fn​n+11​⎠⎟⎟⎞​=⎝⎜⎜⎛​Fn+1​Fn−2​+Fn−1​+n+1n+11​⎠⎟⎟⎞​ 解得 A = ( 0 1 0 0 1 1 0 0 0 1 1 0 0 1 1 1 ) A= begin{pmatrix} 0 & 1 & 0 & 0 \ 1 & 1 & 0 & 0\ 0 & 1 & 1 & 0 \ 0 & 1 & 1 & 1 end{pmatrix} A=⎝⎜⎜⎛​0100​1111​0011​0001​⎠⎟⎟⎞​
求 F n F_n Fn​: A n − 1 ∗ ( F 1 F 2 3 1 ) = ( F n F n + 1 n + 1 1 ) A^{n-1}* begin{pmatrix} F_1 \ F_2\ 3 \ 1 end{pmatrix} = begin{pmatrix} F_n \ F_{n+1} \ n+1 \ 1 end{pmatrix} An−1∗⎝⎜⎜⎛​F1​F2​31​⎠⎟⎟⎞​=⎝⎜⎜⎛​Fn​Fn+1​n+11​⎠⎟⎟⎞​

(3) F n = F n − 2 + F n − 1 , F 1 = F 2 = 1 , 求 F n 的 前 n 项 和 S n F_n=F_{n-2}+F_{n-1},F_1=F_2=1,求F_n的前n项和S_n Fn​=Fn−2​+Fn−1​,F1​=F2​=1,求Fn​的前n项和Sn​

同理求A:
A ∗ ( F n − 2 F n − 1 S n − 2 ) = ( F n − 1 F n S n − 1 ) = ( F n − 1 F n − 2 + F n − 1 S n − 2 + F n − 1 ) A* begin{pmatrix} F_{n-2} \ F_{n-1} \ S_{n-2} end{pmatrix} = begin{pmatrix} F_{n-1} \ F_n\ S_{n-1} end{pmatrix}= begin{pmatrix} F_{n-1} \ F_{n-2}+F_{n-1} \ S_{n-2}+F_{n-1} end{pmatrix} A∗⎝⎛​Fn−2​Fn−1​Sn−2​​⎠⎞​=⎝⎛​Fn−1​Fn​Sn−1​​⎠⎞​=⎝⎛​Fn−1​Fn−2​+Fn−1​Sn−2​+Fn−1​​⎠⎞​
解得 A = ( 0 1 0 0 0 1 1 1 0 0 0 0 1 0 0 0 1 0 1 0 0 1 0 1 1 ) A= begin{pmatrix} 0 & 1 & 0 & 0 & 0\ 1 & 1 & 1 & 0 & 0\ 0 & 0 & 1 & 0 & 0\ 0 & 1 & 0 & 1 & 0\ 0 & 1 & 0 & 1 & 1 end{pmatrix} A=⎝⎜⎜⎜⎜⎛​01000​11011​01100​00011​00001​⎠⎟⎟⎟⎟⎞​

观察上面数各列求出的转换矩阵A,你会发现它们有一些相似性,
一般的,如果有 F n = p ∗ F n − 2 + q ∗ F n − 1 + r ∗ n + s F_n=p*F_{n-2} + q * F_{n-1} + r * n + s Fn​=p∗Fn−2​+q∗Fn−1​+r∗n+s,可构造矩阵A为:
A = ( 0 p 0 0 0 1 q 1 0 0 0 0 1 0 0 0 r 0 1 0 0 s 0 1 1 ) A= begin{pmatrix} 0 & p & 0 & 0 & 0\ 1 & q & 1 & 0 & 0\ 0 & 0 & 1 & 0 & 0\ 0 & r & 0 & 1 & 0\ 0 & s & 0 & 1 & 1 end{pmatrix} A=⎝⎜⎜⎜⎜⎛​01000​pq0rs​01100​00011​00001​⎠⎟⎟⎟⎟⎞​
递推式2: F n = k ∗ F n − 1 + n 2 Fn=k*F_{n-1}+n^2 Fn=k∗Fn−1​+n2
按照之前的方法写:
A ∗ ( F n − 1 n 2 ) = ( F n ( n + 1 ) 2 ) = ( k ∗ F n − 1 + n 2 ( n + 1 ) 2 ) A* begin{pmatrix} F_{n-1} \ n^2 end{pmatrix} = begin{pmatrix} F_n \ (n+1)^2 end{pmatrix}= begin{pmatrix} k*F_{n-1}+n^2 \ (n+1)^2 end{pmatrix} A∗(Fn−1​n2​)=(Fn​(n+1)2​)=(k∗Fn−1​+n2(n+1)2​)易知A是2×2的矩阵,不访设 A = ( a b c d ) A= begin{pmatrix} a & b \ c & d end{pmatrix} A=(ac​bd​)
得到:
a ∗ F n − 1 + b ∗ n 2 = k ∗ F n − 1 + n 2 a*F_{n-1} + b * n^2 = k* F_{n-1} + n^2 a∗Fn−1​+b∗n2=k∗Fn−1​+n2 (式子1)
c ∗ F n − 1 + d ∗ n 2 = ( n + 1 ) 2 = n 2 + 2 n + 1 c*F_{n-1}+d*n^2=(n+1)^2=n^2+2n+1 c∗Fn−1​+d∗n2=(n+1)2=n2+2n+1(式子2)
解到这里你会发现式子2中有一个关于n的一次项2n和一个常数项,此时求出的abcd的值是不对的,因为将abcd带入原式后计算,是得不到 ( n + 1 ) 2 (n+1)^2 (n+1)2这个式子的,所以不能这样构造。那应该怎么构造呢,在式子2中有一个一次项和一个常数项,那就再构造时把一次项和常数项加入。
A ∗ ( F n − 1 n 2 n 1 ) = ( k ∗ F n − 1 + n 2 ( n + 1 ) 2 n + 1 1 ) A* begin{pmatrix} F_{n-1} \ n^2 \ n \ 1 end{pmatrix} = begin{pmatrix} k* F_{n-1}+n^2 \ (n+1)^2 \ n+1 \ 1 end{pmatrix} A∗⎝⎜⎜⎛​Fn−1​n2n1​⎠⎟⎟⎞​=⎝⎜⎜⎛​k∗Fn−1​+n2(n+1)2n+11​⎠⎟⎟⎞​
得
A = ( k 1 0 0 0 1 2 1 0 0 1 0 0 0 0 1 ) A= begin{pmatrix} k & 1 & 0 & 0 \ 0 & 1 & 2 & 1\ 0 & 0 & 1 & 0 \ 0 & 0 & 0 & 1 end{pmatrix} A=⎝⎜⎜⎛​k000​1100​0210​0101​⎠⎟⎟⎞​
递推式3: F n = k ∗ F n − 1 + n 3 F_n=k*F_{n-1}+n^3 Fn​=k∗Fn−1​+n3
同理可求得:
A = ( k 1 0 0 0 0 1 3 3 1 0 0 1 2 1 0 0 0 1 1 0 0 0 0 1 ) A= begin{pmatrix} k & 1 & 0 & 0 & 0\ 0 & 1 & 3 & 3 & 1\ 0 & 0 & 1 & 2 & 1 \ 0 & 0 & 0 & 1 & 1 \ 0 & 0 & 0 & 0 & 1 end{pmatrix} A=⎝⎜⎜⎜⎜⎛​k0000​11000​03100​03210​01111​⎠⎟⎟⎟⎟⎞​
递推式4: F n = k ∗ F n − 1 + b n F_n=k*F_{n-1}+b^n Fn​=k∗Fn−1​+bn
A ∗ ( F n − 1 b n ) = ( F n b n + 1 ) = ( k ∗ F n − 1 + b n b n ∗ b ) A* begin{pmatrix} F_{n-1} \ b^n end{pmatrix}= begin{pmatrix} F_n \ b^{n+1} end{pmatrix}= begin{pmatrix} k*F_{n-1}+b^n \ b^n * b end{pmatrix} A∗(Fn−1​bn​)=(Fn​bn+1​)=(k∗Fn−1​+bnbn∗b​)
解得:
A = ( k 1 0 b ) A= begin{pmatrix} k & 1 \ 0 & b end{pmatrix} A=(k0​1b​)

几道模板题:
1.Fibonacci
2.Tr A
3.A Simple Math Problem

最后

以上就是飘逸老师最近收集整理的关于矩阵快速幂1.快速幂2.矩阵快速幂的全部内容,更多相关矩阵快速幂1内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(307)

评论列表共有 0 条评论

立即
投稿
返回
顶部