Loading

备忘——快速幂相关

前言


对于 \(a^b\),最朴素的方法是将 \(b\)\(a\) 相乘,从而求出结果,然而当 \(b\) 十分大时,这样往往会造成计算时间过长,因此需要一个更好的方法来加快计算的速度,简化计算的步骤。

快速幂


分析


\(2^9 = 512\) 为例,可以将其表示为 \(2^{(8+1)} = 2^{(1*2^3 + 0*2^2 + 0*2^1 + 1*2^0)} = 2^{1*8} *2^{0*4}*2^{0*2}*2^{1*1}\) 。对于 \((9)_{10}\) 来说,以二进制可以表示为 \((1001)_2\),不难发现,将 \((1001)_2\) 转换为 \(9\) 时,使用到了 \(1*2^3 + 0*2^2 + 0*2^1 + 1*2^0 = 9\)。对于 \(2^8,2^4,2^2,2^1\)来说,前一项始终是后一项的平方。至此,快速幂的算法可以总结出来。

代码

public void fastPow(long a,long b,long mod){
    //其中a指的是当前项,b是指数,mod是最终结果需要求余的对象,数值视题目情况而定
    long result = 1;
    while(b> 0){
        if ( b % 2 == 1 ){ //说明幂指数的二进制表示形式的最后一位是1
            result = result * a % mod; //此时需要将结果乘上当前的项
        }
        b >>= 1; //每次循环都要删除掉当前指数的二进制表示形式的最后一位数
        a = (a * a) % mod; //每次循环,前一项项都会是当前项的平方
    }
}

利用快速幂,每次计算的是\(2^8,2^4,2^2,2^1\),这样可以将 \(2^9\) 的计算复杂度由 \(O(n)\) 降到了 \(O(logn)\)

矩阵快速幂


将算数快速幂扩展开来到矩阵的幂,设\(A\)是矩阵,求 \(A\)\(b\) 次方,即求矩阵\(A^b\)

矩阵的乘法


根据矩阵乘法的规律,可以得到两个矩阵乘法的算法代码

public int[][] twoMatrixMutiply(int x [][],int y [][],int mod) {
    int ans[][]=new int[x.length][y[0].length];
    for(int i=0;i<ans.length;i++)
        for(int j=0;j<ans[0].length;j++) {
            ans[i][j]=0;
        }//初始化
    for(int i=0;i<x.length;i++)
        for(int j=0;j<y[0].length;j++)
            for(int p=0;p<x[0].length;p++)
                ans[i][j]+=x[i][p]*y[p][j];
                ans[i][j] % mod
    return ans;
			              
}

代码


矩阵的快速幂可以由算数快速幂的算法拓展而来,只是其中的项与项之间的转换的乘法使用的是矩阵乘法的法则。

public int[][] fastPow(int[][] A,int b,int mod){
    //A为当前项的矩阵,b为指数,mod为求余的对象,视题目要求而定
    int n = A.length;
    int[][] E = new int[n][n];//单位矩阵,也用于保存最终计算结果
    for(int i = 0;i < n;i++){
        E[i][i] = 1;//初始化单位矩阵
    }

    while(b != 0){
        if(b % 2 == 1){mod
            E = twoMatrixMutiply(E,A,mod);
        }
        b >>= 1;
        A = twoMatrixMutiply(A,A,mod)
    }
    return E;
}
posted @ 2020-10-19 17:42  Icdd  阅读(148)  评论(0)    收藏  举报