备忘——快速幂相关
前言
对于 \(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;
}

浙公网安备 33010602011771号