前几天做一个题都快做出来了,结果就是不会快速算幂导致超时。。
快速幂取模我看了2种方法。
首先有公式:
(a+b)%m=(a%m+b%m)%m
(a*b)%m=(a%m*b%m)%m
1.算法导论里的,算a^b mod n,设b[k]是b二进制的最高位(不算符号位)。
Modular-Exponentiation(a, b, n) 1. c = 0 2. d = 1 3. 设<b[k],b[k-1],..b[0]>是b的二进制表示 4. for i=k downto 0 5. do c = 2c 6. d = (d*d) mod n 7. if b[i] = 1 8. then c = c + 1 9. d = (d*a) mod n 10. return d
这里面c其实是没用的,只是在模拟从0到b的过程,c等于b的二进制的前缀,d一直都是a^c mod n。一开始c=0,d=a^0 mod n=1。每次迭代c=2c,所以d=d*d,如果b那一位是1的话就还要再乘以a才能保持d一直是a^c mod n。
到最后c等于b,d就是a^b mod n了。
2.把b变成2进制的形式,比如a^11,b=11,二进制为1011=2^0+2^1+2^3,所以a^b=a^(2^0+2^1+2^3)= a^(2^0)*a^(2^1)*a^(2^3)。因此可以设一个t,每次迭代t=a^(2^i),如果b的二进制第i位(从低往高)不是0,就乘以t。
下面的代码是算x^n,M是要取的模,res是答案,t一开始为a^(2^0)%M,每次迭代n右移一位,使当前要判断的位在最右边,n&1是判断n是否为1。
long long bigpow(int x,int n, int M){
long long res=1,t=x%M;
while(n){
if(n&1){
res=(res*t)%M;
}
t=(t*t)%M;
n>>=1;
}
return res;
}