快速幂简介:
快速幂基于二分的思想,常被称为二分幂。快速幂基于两个事实:
①若b为奇数,则a^b = a * a^(b-1)。
②若b为偶数,则a^b = a^(b/2) * a^(b/2)。
问题引入:
给定三个正整数a、b、m(a<10^9, b<10^6, 1<m<10^9 ),求a^b%m的值。
typedef long long LL;
LLpow(LL a, LL b, LL m){
LL ans = 1;
for(int i = 0; i < b ; i++){
ans = ans * a % m;
}
return ans;
}//时间复杂度O(b)
若给定三个正整数a、b、m(a<10^9, b<10^18, 1<m<10^9 ),求a^b%m的值。
对于这个问题,再使用上面的方法就不可以了,O(b)的时间复杂度无法支持10^18。因此来到了快速幂的高光时刻!!!
快速幂递归写法代码实现:
typedef long long LL;
LLbinaryPow(LL a, LL b, LL m){
if (b == 0)
return 1; //a^0=1
if(b & 1) //b为奇数,转换为b-1
return a * binaryPow(a, b-1, m) % m;
else{ //b为偶数,转换为b/2
LL ans = binaryPow(a, b/2, m);
return ans * ans % m;
}
}//时间复杂度O(logb)
针对不同的题目,需要注意两个方面:
①如果初始时a有可能大于等于m,就需要在进入函数前让a对m取模。
②如果m为1,可以直接在函数外部判定为0,不需要进入函数进行计算(任意正整数对1取模等于0)。
关于快速幂的迭代写法:
对a来说,如果把b写成二进制,b就可以写成若干二次幂的和。例如13的二进制是1101,3号位、2号位、0号位都是1,那么就可以得到13=2^3 +2^2 +2^0=8+4+1,所以 a^13 =a^(8+4+1)= a^8 * a^4 * a^1。
因此可得快速幂迭代写法的一般思路:
①初始化令ans=1,存放累积的结果。
②判断b的二进制末尾是否为1 (也就是判断b是否为奇数),如果是,则令ans乘上a的值。
③令a平方,并将b右移一位(也就是将b除以2)。
④只要b大于0,就返回②。
快速幂迭代写法代码实现:
typedef long long LL;
LLbinaryPow(LL a, LL b, LL m){
LL ans = 1;
while(b > 0){
if(b & 1) { //b为奇数
ans = ans * a % m; //令ans乘上a的值
}
a = a * a % m; //令a平方
b >>= 1; //将b的二进制右移1位
}
return ans;
}