让幂运算更效率——快速幂
在日常解决问题的过程中,我们常常会遇到求ab类似的问题,对于这种问题,我们一般的解决方法就是最朴素的方法就能解决,它的时间复杂度为O(b)。
1 int power(int a,int b) //求a的b次方 2 { 3 int i,ans=1; 4 for(i=0;i<b;i++) 5 ans*=a; 6 return ans; 7 }
但是对于某些题目,当b的数据变大的时候,可能就会超时,这时候我们就需要用快速幂来优化我们的程序了。
一、快速幂
快速幂的原理来自于十进制二进制相互转换的加权系数法,对于任意一个十进制数,我们可以把它写成2k1+2k2+2k3+…+2kn+…(k=0,1,2…),继而转化为二进制,如10=21+23=(1010)2。那么对于ab的次数b来说,也是如此。我们可以把b拆成2k1+2k2+2k3+…+2kn+…(k=0,1,2…),那么ab就变成了a(2^k1+2^k2+2^k3+…+2^kn+…)(k=0,1,2…),继而可以化成a2^k1×a2^k2×a2^k3×…×a2^k1。这样一来,我们就把原来的时间复杂度O(b)压缩到O(log2b),这是一个很可观的改进。
怎么用代码来实现呢?这里我们需要用到两个位运算&和>>,其中&是按位与,我们在代码中用(n&1)来判断n的二进制最后一位是不是1。n>>1的作用是二进制数左移一位,效果等同于除以2,但是时间要比除以2稍快。
综上,我们就可以得到快速幂的实现代码了。
快速幂的原理来自于十进制二进制相互转换的加权系数法,对于任意一个十进制数,我们可以把它写成2k1+2k2+2k3+…+2kn+…(k=0,1,2…),继而转化为二进制,如10=21+23=(1010)2。那么对于ab的次数b来说,也是如此。我们可以把b拆成2k1+2k2+2k3+…+2kn+…(k=0,1,2…),那么ab就变成了a(2^k1+2^k2+2^k3+…+2^kn+…)(k=0,1,2…),继而可以化成a2^k1×a2^k2×a2^k3×…×a2^k1。这样一来,我们就把原来的时间复杂度O(b)压缩到O(log2b),这是一个很可观的改进。
怎么用代码来实现呢?这里我们需要用到两个位运算&和>>,其中&是按位与,我们在代码中用(n&1)来判断n的二进制最后一位是不是1。n>>1的作用是二进制数左移一位,效果等同于除以2,但是时间要比除以2稍快。
综上,我们就可以得到快速幂的实现代码了。
1 long long fastpow(long long n,long long multi) 2 { 3 long long ans=1,base=n; 4 while(multi) 5 { 6 if(multi&1) ans=(ans*base); 7 base=(base*base); 8 multi>>=1; 9 } 10 return ans; 11 }
但是在实际解题中很多情况下进行不了几次幂运算就会溢出,所以常常会让我们取模,下面我们来解决这个问题。
二、快速幂取模
求解快速幂取模的问题并不需要对算法做太多的改动,在乘运算时加上取模即可,但要注意取模尽量要考虑全面,因为不一定什么地方就会爆掉了。
代码如下:
代码如下:
1 long long fastpow(long long n,long long multi,long long mod) 2 { 3 long long ans=1,base=n; 4 while(multi) 5 { 6 if(multi&1) ans=(ans*base)%mod; 7 base=(base*base)%mod; 8 multi>>=1; 9 } 10 return ans%mod; 11 }
三、矩阵快速幂
(施工中orz)
代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 long long mod,n,multi; 6 7 long long fastmulti(long long n,long long multi,long long mod) 8 { 9 long long ans=1,base=n; 10 while(multi) 11 { 12 if(multi&1) ans=(ans*base)%mod; 13 base=(base*base)%mod; 14 multi>>=1; 15 } 16 return ans%mod; 17 } 18 19 int main() 20 { 21 scanf("%lld%lld%lld",&n,&multi,&mod); 22 long long ans; 23 ans=fastmulti(n,multi,mod); 24 printf("%lld^%lld mod %lld=%lld",n,multi,mod,ans); 25 return 0; 26 }
Author : Houge Date : 2019.6.2
Update log :