快速幂取模

来源:互联网 发布:国家漏洞数据库 编辑:程序博客网 时间:2024/06/06 08:31

快速幂取模(快速的求一个幂式的模(),通常是大数取余的运算

 




1.模运算:

(a+b)%m=(a%m+b%m)%m

(a-b)%m=(a%m-b%m)%m

(a*b)%m=(a%m*b%m)%m




2.位运算

 &    按位与
 >>    右移,正数高位补0,负数由计算机决定




按位与运算

按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0。参与运算的数以补码方式出现。
例如:9&5可写算式如下:
    00001001      (9的二进制补码)
  &00000101    (5的二进制补码)
    00000001       (1的二进制补码)
可见9&5=1。
按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清 0 ,保留低八位,可作a&255运算(255 的二进制数为0000000011111111)。




右移运算

右移运算符“>>”是双目运算符。其功能是把“>>”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数。例如:
    设  a=15,
    a>>2
表示把000001111右移为00000011(十进制3)。

注意:对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定。TurboC和很多系统规定为补

还可以判断奇偶x&1==0为偶,x&1==1为奇

(b>>=1)相当于 b/2

 



核心原理:(引用

对于任何一个整数的模幂运算

a^b%c

对于b我们可以拆成二进制的形式

b=b0+b1*2+b2*2^2+...+bn*2^n

这里我们的b0对应的是b二进制的第一位

那么我们的a^b运算就可以拆解成

a^b0*a^b1*2*...*a^(bn*2^n)

对于b来说,二进制位不是0就是1,那么对于bx为0的项我们的计算结果是1就不用考虑了,我们真正想要的其实是b的非0二进制位

 

那么假设除去了b的0的二进制位之后我们得到的式子是

a^(bx*2^x)*...*a(bn*2^n)

这里我们再应用我们一开始提到的公式,那么我们的a^b%c运算就可以转化为

(a^(bx*2^x)%c)*...*(a^(bn*2^n)%c)

这样的话,我们就很接近快速幂的本质了

(a^(bx*2^x)%c)*...*(a^(bn*2^n)%c)

我们会发现令

A1=(a^(bx*2^x)%c)

...

An=(a^(bn*2^n)%c)

这样的话,An始终是A(n-1)的平方倍(当然加进去了取模匀速那),依次递推



================================================

如:2^5=2^(0101)=2^(1+2^2)=(2^1)*(2^2)

5=0*2^3+1*2^2+0*2^1+1*2^0

 

===================================================

 

代码的实现

Int pow_mod(int a,int b,int c){         intans=1;   //记录结果         a=a%c;   //预处理,使得a处于c的数据范围之下         while(b)         {                  if(b&1)ans=(ans*a)%c;   //如果b的二进制位不是0,那么我们的结果是要参与运算的                  b>>=1;    //二进制的移位操作,相当于每次除以2,用二进制看,就是我们不断的遍历b的二进制位b/=2;                  a=(a*a)%c;   //不断的加倍 累乘 幂的改变         }         returnans;}


 注意 一般数很大,故:typedef long long ll;


一句话:因子取余相乘后再取余,余数不变。

原创粉丝点击