• 快速幂、矩阵快速幂


    快速幂

    所谓快速幂,就是用来快速求取 a n a^n an的算法,当 n n n不大时,或者需要求取的次数不多时,我们可以直接进行 n n n次遍历求取即可,当 n n n的很大或者需要多次求取时,我们有一种更为快速的算法来求解,有多快?— O ( l o g n ) O(log n) O(logn)
    我们考虑 a n ,分解 n ,即将 n 转化为二进制形式,假设 n = 27 则, a 27 = a ( 11011 ) 2 进制 = a ( 10000 ) 2 ∗ a ( 1000 ) 2 ∗ a ( 10 ) 2 ∗ a ( 1 ) 2 = a 16 ∗ a 8 ∗ a 2 ∗ a 1 = a 27 . . . . . . . ( 对 n 进行二进制分解 ) 我们考虑a^n,分解n,即将n转化为二进制形式,假设n=27\\ 则,a^{27}=a^{(11011)_{2进制}}=a^{(10000)_2}*a^{(1000)_2}*a^{(10)_2}*a^{(1)_2}\\ =a^{16}*a^{8}*a^2*a^1=a^{27}.......(对n进行二进制分解) 我们考虑an,分解n,即将n转化为二进制形式,假设n=27则,a27=a(11011)2进制=a(10000)2a(1000)2a(10)2a(1)2=a16a8a2a1=a27.......(n进行二进制分解)
    那么我们根据上面的分解步骤就可以的到,
    当前n的二进制位值第x为1时,只需要乘上 a 2 x a^{2^x} a2x即可,并且每次a*a,就能得到下一个位置x+1的 a 2 x + 1 a^{2^{x+1}} a2x+1
    我们直接来看代码
    例题:acwing875. 快速幂
    代码如下:

    #include
    #include
    #include
    #include
    using namespace std;
    typedef long long ll;
    int ks(int a,int b,int p){
        int res=1;
        while(b){
            if(b&1) res=(ll)res*a%p;
            a=(ll)a*a%p;
            b>>=1;
        }
        return res%p;
    }
    int main(){
        int t,a,b,p;;
        cin>>t;
        while(t--){
            scanf("%d%d%d",&a,&b,&p);
            printf("%d\n",ks(a,b,p));
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    矩阵快速幂

    矩阵快速幂=快速幂+矩阵乘法

    首先,我们先了解一下矩阵乘法的规则:
    在这里插入图片描述
    矩阵 A 要想与矩阵 B 相乘,那么矩阵 A 的列数就得等于矩阵 B 的行数 即, C a × b = A a × p × B p × b 所得新矩阵 C 的行数等于矩阵 A 的行数,列数等于矩阵 B 的列数 矩阵A要想与矩阵B相乘,那么矩阵A的列数就得等于矩阵B的行数\\ 即,C_{a\times b}=A_{a\times p}\times B_{p\times b}\\ 所得新矩阵C的行数等于矩阵A的行数,列数等于矩阵B的列数 矩阵A要想与矩阵B相乘,那么矩阵A的列数就得等于矩阵B的行数即,Ca×b=Aa×p×Bp×b所得新矩阵C的行数等于矩阵A的行数,列数等于矩阵B的列数
    由斐波那契数列来来引出矩阵快速幂
    f [ n ] = { f [ n − 1 ] + f [ n − 2 ] , n > 1 f [ 1 ] = 1 f [ 0 ] = 0 可以写成 [ f [ n ] 0 f [ n − 1 ] 0 ] = [ 1 1 1 0 ] × [ f [ n − 1 ] 0 f [ n − 2 ] 0 ] = [ 1 1 1 0 ] 2 × [ f [ n − 2 ] 0 f [ n − 3 ] 0 ] 依次类推可得: [ f [ n ] 0 f [ n − 1 ] 0 ] = [ 1 1 1 0 ] n − 1 × [ f [ 1 ] 0 f [ 0 ] 0 ] f[n]=

    {f[n1]+f[n2],n>1f[1]=1f[0]=0" role="presentation">{f[n1]+f[n2],n>1f[1]=1f[0]=0
    \\ 可以写成
    [f[n]0f[n1]0]" role="presentation">[f[n]0f[n1]0]
    =
    [1110]" role="presentation">[1110]
    \times
    [f[n1]0f[n2]0]" role="presentation">[f[n1]0f[n2]0]
    =
    [1110]" role="presentation">[1110]
    ^2\times
    [f[n2]0f[n3]0]" role="presentation">[f[n2]0f[n3]0]
    \\依次类推可得:\\
    [f[n]0f[n1]0]" role="presentation">[f[n]0f[n1]0]
    =
    [1110]" role="presentation">[1110]
    ^{n-1}\times
    [f[1]0f[0]0]" role="presentation">[f[1]0f[0]0]
    f[n]= f[n1]+f[n2],n>1f[1]=1f[0]=0可以写成[f[n]f[n1]00]=[1110]×[f[n1]f[n2]00]=[1110]2×[f[n2]f[n3]00]依次类推可得:[f[n]f[n1]00]=[1110]n1×[f[1]f[0]00]
    也就是说,我们只需要算出 [ 1 1 1 0 ] n − 1
    [1110]" role="presentation">[1110]
    ^{n-1}
    [1110]n1
    即可求出 [ f [ n ] 0 f [ n − 1 ] 0 ]
    [f[n]0f[n1]0]" role="presentation">[f[n]0f[n1]0]
    [f[n]f[n1]00]
    ,而 [ 1 1 1 0 ] n − 1
    [1110]" role="presentation">[1110]
    ^{n-1}
    [1110]n1
    我们可以用快速幂的思想在 O ( l o g n ) O(log n) O(logn)的时间复杂度内求出。
    例题:acwing205. 斐波那契
    代码如下:

    #include
    #include
    #include
    #include
    using namespace std;
    typedef long long ll;
    const int P=10000; 
    
    struct node{
        int data[5][5];
    };
    node mul(node a,node b){//矩阵乘法
        node res;
        memset(res.data,0,sizeof res.data);
        for(int i=1;i<=2;i++)
            for(int j=1;j<=2;j++)
                for(int k=1;k<=2;k++)
                    res.data[i][j]=(res.data[i][j]+(ll)a.data[i][k]*b.data[k][j]%P)%P;
        return res;
    }
    
    node ks(node a,int b){//快速幂
        node res;
        memset(res.data,0,sizeof res.data);
        for(int i=1;i<=2;i++) res.data[i][i]=1;
        while(b){
            if(b&1) res=mul(res,a);
            b>>=1;
            a=mul(a,a);
        }
        return res;
    }
    
    int main(){
        int n;
        while(scanf("%d",&n)&&n!=-1){
            if(!n){
                printf("0\n");
                continue;
            }
            node f,base;
            f.data[1][1]=1;f.data[1][2]=0;//初始斐波那契数列
            f.data[2][1]=0;f.data[2][2]=0;
            
            base.data[1][1]=1;base.data[1][2]=1;//构建矩阵
            base.data[2][1]=1;base.data[2][2]=0;
            
            node ant=ks(base,n-1);
            
            node res=mul(ant,f);
            
            cout<<res.data[1][1]<<endl;
            
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    斐波那契数列差不多是最简单的矩阵快速幂的应用,矩阵快速幂的难点在于如何构建一个矩阵,使其能够满足递推式。

  • 相关阅读:
    简单实现接口自动化测试(基于python)
    K-最近邻算法
    Java-数据类型与变量
    java lombok
    【小程序项目开发 -- 京东商城】uni-app 商品分类页面(下)
    IO示例练习
    mysql数据库 - 统诉
    npm更换成淘宝镜像源及cnpm使用
    蜜雪冰城涨价怒赞无数 雪王张红超卷出一条阳道
    MATLAB算法实战应用案例精讲-【数模应用】批量梯度下降(BGD)(附MATLAB、R语言、Python和C++代码)
  • 原文地址:https://blog.csdn.net/qq_43851311/article/details/127415585