当需要对一个比较大数的比较大幂进行求模时,如果先计算这个数的值,然后再求模,结果容易产生溢出。比如计算 1234567mod17 先计算左边部分效率将变得十分低下,利用快速幂求模
可以快速得到计算结果
- 模运算满足交换律
(a×b)modm=(amodm)×(bmodm)modm
利用这一定律,可以对每次乘法运算的结果进行求模,避免了位数溢出的问题,但是还存在效率较低的问题,复杂度为O(n)
- 通过位运算来减少运算次数
通过位运算可以快速的进行幂交换计算,利用二分法可以快速得到求模结果。
a2nmodm=(anmodm)2modm
我们以实际的案例来说明这个算法,比如求下列式子的值:
1234567mod17
因为567的二进制是0b1000110111
,那就说
567=512+32+16+4+2+1
也就是: 1234567mod17 可以写成:
1234512×123432×12344×12342×12341mod17
利用模运算交换律:
(1234512mod17)×(123432mod17)×(12344mod17)×(12342mod17)×(12341mod17)mod17
其中:
12342mod17=(12341mod17)×(12341mod17)mod1712344mod17=(12342mod17)×(12342mod17)mod17...1234512mod17=(1234256mod17)×(1234256mod17)mod17
那么利用每一步的结果可以计算出来不同次方的mod值,从而避免了重复计算。
O(logN),实际循环次数:log2N
C++版本,求 anmodm,这里用long long视具体的情况而定
int pow_mod(long long a, int n, int m){
long long ans = 1;
a %= m;
while(n){
if(n&1) ans = ans * a % m;
a = a * a % m;
n >>= 1;
}
return ans;
}