快速幂取模

  几天做一个题都快做出来了,结果就是不会快速算幂导致超时。。委屈

  快速幂取模我看了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;
}


你可能感兴趣的:(快速幂取模)