一、引入
当我们遇到一个很简单的问题,例如计算 a b m o d n a^b \mod n abmodn 的结果,我们可以使用多个循环迅速解决,时间复杂度约为 O ( b ) O(b) O(b)
代码就像这样:
sum=1;
for(int i=1;i<=b;++i){
sum=sum*a%m;
}
cout<<sum;
当然,如果是一些简单的题目,自然没有任何的问题,但是当我们遇到需要快速求解的题目或需要求解多个时,显然会超时,因此,我们需要考虑如何优化这一个算法
二、快速幂
对于一个线性求解的问题,我们往往可以使用分治的思想,例如:
对于 a b a^b ab,当 b b b 是偶数时, a b a^b ab 就可以拆分成 a b ÷ 2 + a b ÷ 2 a^{b\div 2}+a^{b\div 2} ab÷2+ab÷2 同理,当 b b b 为奇数时, a b a^b ab 就可以拆分成 a b ÷ 2 + a b ÷ 2 × a a^{b \div 2}+a^{b\div 2}\times a ab÷2+ab÷2×a ,然后通过一次乘法运算,就可以获得 a b a^b ab 的结果。我们只需要继续递归上述计算方法, b b b 最终一定会分解到 1 ,这种计算方法就叫做快速幂算法。
代码实现上述算法:
int pow(int a,int b,int n){ // a,b,n 与 a^b mod n 对应
if(b==1) return a; //当 b 已经分解到 1 的时候,返回 a,否则继续分解
if(b%2==0){ //判断 b 是偶数还是奇数
int t=pow(a,b/2,n); //如同上面所描述的方法,把 a^b 分解为 a^(b÷2)×a^(b÷2)
return t*t%n; //返回计算结果,也就是 a^(b÷2)×a^(b÷2)%n
} else {
int t=pow(a,b/2,n); //如同上面所描述的方法,把 a^b 分解为 a^(b÷2)×a^(b÷2)×a
return t*t*a%n; //返回计算结果,也就是 a^(b÷2)×a^(b÷2)×a%n
}
}
非递归的代码如下(原理一样,就不做过多解释了):
int pow(int a, int b) {
int ans=1,base=a;
while(b!=0) {
if(b&1)//判断b的奇偶
ans*=base;//当n为奇数时,乘以base(当前权值下的a)
base*=base;
b>>=1;//等价于b/=2
}
return ans;
}
还有有疑问可以在此处寻找更多优秀文章或者在评论中提出哦~