首页 > 代码库 > 快速幂(讲解)

快速幂(讲解)

对于快速幂有人会问:要快速幂干什么,cmath库里的pow就很好用啊!

但是你有没有想过他的时间复杂度!假设我们要求a^b,按照朴素算法就是把a连乘b次,这样一来时间复杂度是O(b)也即是O(n)级别,况且有些大佬说:用stl比用循环还慢。但是我们在这里所说的快速幂的目的就是做到快速求幂,快速幂能做到O(logn),快了好多好多。

快速幂的原理是用二分及二进制优化的。

假设我们要求a^b,那么我们在这里如果我们要用快速幂来做这道题,我们可以把b拆成二进制,该二进制的第i位的权为2^(i-1),例如:

当b==11时,a^11=a^(2^0+2^1+2^3)

11的二进制是1011,11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1,因此,我们将a¹¹转化为算 a^(2^0)*a^(2^1)*a^(2^3) 有没有发现现在就快多了?

(⊙o⊙)…貌似这两项也不是很好求的样子。。。。

没事,我们在下面还会讲到的。

由于是二进制,很自然地想到用位运算这个强大的工具: &  和 >>   

  &运算通常用于二进制取位操作,例如一个数 & 1 的结果就是取二进制的最末位。还可以判断奇偶x&1==0为偶,x&1==1为奇。
  >>运算比较单纯,二进制去掉最后一位。
不多说了,先来看看代码吧。

 各种模板

    one。快速幂普通版(未取模)

int kpow(int n,int k){     long long int res=1;    while(k)    {        if(k&1) res*=n;        n*=n;        k=k>>1;//每次都将k/2,为使用的二进制,使改代码更快。     }    return res;}

    two。快速幂取余版

int kpow(long long  n,long long  k,long long  mod){     long long int res=1;    while(k)    {        if(k&1) res=(res*n)%mod;        n=(n*n)%mod;        k=k>>1;//每次都将k/2,为使用的二进制,使改代码更快。     }    return res;}

three。由于若题目数据太大,会使快速幂时由于是先乘后取余,乘后会导致越界,故可采用模拟乘法,在模拟乘法过程中取余数

  即模拟乘法+快速幂

int qpow(long long n,long long k,long long mod){    long long int res=1;    while(k)    {        if(k&1) res=(res*n)%mod;        n=(n*n)%mod;        k=k>>1;    }    return res;}/******************华丽的分割线*****************************/               /****模拟乘法****/ int Analog multiplication(long long n,long long k,long long mod){    long long  res=0;    while(k)    {        if(k&1)res=(res+n)%mod;        n=(2*n)%mod;        k=k>>1;        }        return res;}            /****快速幂****/ int qpow(long long n,long long k,long long mod){    long long res=1;    while(k)     {        if(k&1) res=Analog multiplication(n,k,mod);        n=Analog multiplication(n,n,mod);        k=k>>1;    }    return res;}

代码很短,死记也可行,但最好还是理解一下吧,其实也很好理解,以b==11为例,b=>1011,二进制从右向左算,但乘出来的顺序是 a^(2^0)*a^(2^1)*a^(2^3),是从左向右的。我们不断的让n*=n目的即是累乘,以便随时对ans做出贡献。

  其中要理解n*=n这一步,看:::n*n==n^2,下一步再乘,就是n^2*n^2==n^4,然后同理  n^4*n4=n^8,,,,,see?是不是做到了n-->n^2-->n^4-->n^8-->n^16-->n^32.......指数正是 2^i 啊,再看上  面的例子,a¹¹= a^(2^0)*a^(2^1)*a^(2^3),这三项是不是完美解决了,,嗯,快速幂就是这样。

  顺便啰嗦一句,由于指数函数是爆炸增长的函数,所以很有可能会爆掉int的范围,根据题意决定是用 long long啊还是unsigned int啊还是mod某个数啊自己看着办。

 

快速幂(讲解)