快速幂运算
幂运算又叫指数运算,既是a的n次累乘。
快速幂运算中我们用到了蒙哥马利幂算法。将时间复杂度从O(n)降到O(logN)。
具体原理参考:
二进制拆分
快速幂-反复平方法
代码如下:
long long qpow (long long a,long long b){
long long result=1;
while (b){
if (b&1)
result*=a;
b>>=1;
a=a*a;
}
return result;
}
取模取余的区别
下面以整型 a 和 b 两个变量举例,在我们常说的取余运算中,其算法会分成以下的两个步骤:
- 求整数商:c = a / b
- 求余数:r = a - c * b
取模与取余不同在于第一步,求余在整除的时候是往 0 方向逼近,而取模是往负无穷方向逼急。这样就造成了在对负数进行取模运算的差异。所以在计算 -7 % 4 的时候,求余运算的结果是 -3,而取模运算是 1。
/// 第一步:求整数商
// 求余运算
-7 / 4 = -1 (逼近 0 )
// 求模运算
-7 / 4 = -2 (逼近负无穷)
/// 第二步:
// 求余运算
-7 - (-1) * 4 = -7 + 4 = -3
// 求模运算
-7 - (-2) * 4 = -7 + 8 = 1
当然,逼近方向其实不影响其他的运算规律,因为任意的 a % b,对于给定的 a 和 b ,计算结果一定是一个确定的值。所以我们只需了解这两种计算的区别就可以。
不同的编程语言对于 % 的处理是不一样的。Python中的%运算是按求模运算,C/C++/Java是按求余运算。
快速幂取模运算
(a * b) mod n =[(a mod n) * (b mod n)] mod n
将上面公式与快速幂运算算法结合起来。
代码:
long long qpowmod (long long a,long long b,long long mod){
long long result=1;
while (b){
if (b&1)
result=(result*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return (result);
}
快速积运算
求两个数的乘积。
将其中一个数由十进制转换为二进制。再运用分配律。
例如:
a * 15 = a * (1111)2 =a * 23 * 1 + a * 22 * 1 + a * 21 * 1 + a * 20 * 1
代码:
long long qmul(long long a,long long b) {
long long ans=0;
while(b){
if(b&1)
ans+=a;
a=a*2;
b>>=1;
}
return ans;
}
快速积取模
(a * b) mod n =[(a mod n) * (b mod n)] mod n
(a + b) mod n =[(a mod n) + (b mod n)] mod n
long long qmulmod(long long a,long long b,long long mod) {
long long ans=0;
while(b){
if(b&1)
ans=(ans+a)%mod;
a=(a*2)%mod;
b>>=1;
}
return ans%mod;
}