快速幂取模

来源:互联网 发布:守望先锋各个性能数据 编辑:程序博客网 时间:2024/06/02 04:18
快速幂取模算法



例如:求a^b % c 

算法1.

int ans = 1;

for(int i = 1;i<=b;i++)
      ans = ans * a;

ans = ans % c;


这个算法的时间复杂度体现在for循环中,为O(b).这个算法存在着明显的问题,如果a和b过大,很容易就会溢出。



算法2:     

int ans = 1;       //  a^b%c = (a%c)^b%c
a = a % c; //加上这一句
for(int i = 1;i<=b;i++)
       ans = ans * a;

ans = ans % c;




算法3:

int ans = 1;

a = a % c;                    //加上这一句
for(int i = 1;i<=b;i++)
    ans = (ans * a) % c;      //这里再取了一次余

ans = ans % c;


这个算法在时间复杂度上没有改进,仍为O(b),不过已经好很多的,但是在c过大的条件下,还是很有可能超时,



快速幂算法依赖于以下明显的公式。



算法4:

int ans = 1;

a = a % c;
if(b%2==1)

       ans = (ans * a) mod c;     //如果是奇数,要多求一步,可以提前算到ans中

k = (a*a) % c;                   //我们取a^2而不是a

for(int i = 1;i<=b/2;i++)

      ans = (ans * k) % c;

ans = ans % c;


我们可以看到,当我们令k = (a * a) mod c时,状态已经发生了变化,我们所要求的最终结果即为k^(b/2) mod c而不是原来的a^b mod c,所以我们发现这个过程是可以迭代下去的。当然,对于奇数的情形会多出一项a mod c,所以为了完成迭代。当b是奇数时,我们通过ans = (ans * a) % c来弥补多出来的这一项,此时剩余的部分就可以进行迭代了。

形如上式的迭代下去后,当b=0时,所有的因子都已经相乘,算法结束。于是便可以在O(log b)的时间内完成了。


算法5:快速幂算法

int ans = 1;

a = a % c;

while(b>0)
{
  if(b % 2 == 1)      // 如果b是奇数时
      ans = (ans * a) % c;

  b = b/2;

  a = (a * a) % c;

}


将上述的代码结构化,也就是写成函数:

int PowerMod(int a, int b, int c)

{
  int ans = 1;
  a = a % c;
  while(b>0)
  {
     if(b % 2 = = 1)            // 如果b是奇数时
          ans = (ans * a) % c;
     b = b/2;
     a = (a * a) % c;
  }
  return ans;

}

本算法的时间复杂度为O(logb),能在几乎所有的程序设计(竞赛)过程中通过,是目前最常用的算法之一。




0 0
原创粉丝点击