快速幂模板及讲解

Posted fjyyc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速幂模板及讲解相关的知识,希望对你有一定的参考价值。

(这篇其实是我用来练习公式编辑器滴,所以讲的内容略水,大佬们也赏脸看看吧)

定义

快速幂即快速求幂(下文为求a的x次幂模m的结果),但我们一般只在要求对一个数的幂取模时才使用,因为有可能结果很大,有可能long long都存不下,但是因为我们有:
((ab)\%m=(a\%m)(b\%m))
通过转换,可得:
((a^x)\%m)
(= (a imes a imes a imes … imes a(共x个a相乘))\%m)
(= (a\%m) imes (a imes a imes a imes … imes a(共x-1个a相乘))\%m)
(=((a\%m) imes a\%m) imes (a imes a imes a imes … imes a(共x-2个a相乘))\%m)
[……]
按照这个规律可以一直分解下去,有点类似递归的思想,这样对没一次乘都取模,计算的过程中就不会内存爆炸了

但是只按照上面的方法分解时间复杂度是(O(x)),明显不够优秀(摊手手),快速幂一般那个(x)都是极其变态滴,比如x都是(10^8)级别的,或者有时候还要求很多次的快速幂,这个复杂度明显凉了,但是我们正统的快速幂算法只要(O(log(x)))的时间复杂度,这样就算x真的取(10^8)也才(O(27))是不是贼快,接下来我就来介绍一下怎么实现

思路

先来说说递归的思路:

int modpow(int a,int x,int mod){……}
表示求a的x次幂,结果对mod取这个算法的核心就是用平方的方法来省事
如果x为偶数,设(x=2 imes k)
(a^x=a^{2k}=(a^k)^2)
然后递归调用modpow(a,x/2,mod)就可以得到(a^k)
定义一个新变量(比如tmp)把这个结果存储起来
然后tmp=(tmp imes tmp)%mod;
此时的tmp就是(a^{2k})(a^x)
如果x为奇数,设(x=2 imes k+1)
(a^x=a^{2k+1}=(a^k)^2 imes a)
(a^{2k})还是要求的,所以上面的步骤还是要做(因为是整除,所以x/2在这里于是等于k)
所以可以在上面的步骤做完后判断一下
if(x%2==1)//即x为奇数
tmp=(tmp*a)%mod;
特别的,如果x为0,立刻返回1(这个肯定没毛病吧)
于是我们的快速幂递归版就闪亮登场了:

int modpow(int a,int x,int mod)//求a的x次幂的递归法,结果对mod取模
{
  if(x==0)
    return 1;
  int tmp=modpow(a,x/2,mod); 
  tmp=(tmp*tmp)%mod;//这里tmp就已经是a的2k次幂
  if(x%2==1)//如果x是奇数
    tmp=(tmp*a)%mod;
  return tmp;
}
然后是非递归思路:

这个方法比较玄学,可以参考一下(我还是比较喜欢递归法)
核心思路是这样的,我们把x转换为二进制,答案初值赋为1,然后如果从右往左数第k位是1,就把答案乘上(a^{k^2}),同时在枚举二进制下的x的位数时可以顺便把(a^{k^2})搞了,可以用一个while实现以上步骤,复杂度同样是(O(log(x)))(是不是听不懂,没关系看看代码吧):

int poww(int a,int x,int mod){//求a的x次幂的非递归法,结果对mod取模
  int ans=1,base=a;
  while(x>0){
    if(x%2==1)//如果当前这位为1
      ans=(ans*base)%mod;
    base=(base*base)%mod;//这里处理的是a的2k次幂
    x/=2;//这样下一次处理的就是x在二进制下的下一位
  }
  return ans;
}

OK这篇模板讲解就到这咯,一般不会有题目会要求直接求快速幂,可能会换个马甲,也有时候会是一道综合的题目里一个小部分,反正就是不用当心求a的x次方时会超时或超内存,快速幂很优秀

























以上是关于快速幂模板及讲解的主要内容,如果未能解决你的问题,请参考以下文章

数论——快速幂,模运算及快速幂求逆元

[数论+模板] 快速幂及快速幂求逆元算法模板(模板)

快速幂讲解-And-AcWing-89. a^b

快速幂讲解-And-AcWing-89. a^b-《算法竞赛进阶指南》

快速幂(讲解)

常用算法模板 | 快速幂