Live2D

快速幂学习笔记

背景:给定\(a\)\(b\)\(m\),求 \(a^b \mod m\)

常规方法:

\(O(n)\)的时间复杂度,循环一遍即可,程序如下(用pow函数也可):

#include <iostream>
using namespace std;

int a,b,m;
int ans=1;

int main() {
    cin>>a>>b>>m;
    for(int i=1;i<=b;i++)
        ans*=a;
    cout<<ans%m;
    return 0;
}

当然,如果\(a\)\(b\)足够大时,上述程序时肯定不行滴

所以引进我们的\(dalao\)

STL快速幂

比如说:求\(4^{10}\)

常规方法

\(4^{10}=4\times4\times4\times4\times4\times4\times4\times4\times4\times4\),一共\(10\)

快速幂呢?

\(4^{10}=4^8\times4^2=(4^4)^2\times(4^1)^2=((4^2)^2)^2\times(4^1)^2=(((4^1)^2)^2)^2\times(4^1)^2\)

原理:

将指数\((10)_{10}\)转化为\((1010)_2\)
然后\((1010)_2\) 等价于 \(2^3+2^1\)
所以\(4^{10}=4^{2^3}\times4^{2^1}=4^8\times4^2\)

为什么要这么做?

因为只需要乘4次!!!!!!

第1次;\(4^2\)\(4^1\times4^1\)即由\(4\times4\)得到

第2次;\(4^4\)\(4^2\times4^2\)得到

第3次:\(4^8\)\(4^4\times4^4\)得到

第4次:\(4^{10}\)\(4^8\times4^2\)得到,结束

而且,位运算快!

所以时间复杂度就由 \(O(n)\) 降到了 \(O(\log n)\)岂不美哉?

所以接下来,我们就得写代码了:

可以说这个模板是最简单的?


// a^b%m 模板
int qmi(int a,int b,int m){
    int res=1;
    while(b){
        if (b&1) res=1LL*res*a%m;  // b&1 等价于 b%2==1
        a=1LL*a*a%m;
        b>>=1;  // b/=2 
    }
    return res;
}

首先,int res=1;不必说,\(res\)为结果

然后while(b){......} 相当于拆分指数 \(b\)

然后……敲黑板!!!

  • if (b&1) 实乃精华

    为什么?

    举个例子吧

    比如指数\(b=(26)_{10}=(11010)_2\)

    接着:\(b\& 1\)进行运算

    即为:\(11010 \& 00001=0\),为假,所以不执行res=res*a;

    这个时候,有没有发现什么?

    正好与\((11010)_2\)的最后一位相符

    如果再执行下面的b>>=1;,再返回回来执行依然如此

    所以我们可以发现:

    b&1等价于b%2==1

再然后,执行res=res*a;,即为:\(4^2\)\(4^1\times4^1\)即由\(4\times4\)得到

下一步:

目标:

\(4^4\)\(4^2\times4^2\)得到

这里呢,我们发现:\(4^1\)变成了\(4^2\),即\((4^1)^2\)

所以得有一句:a=a*a;

再然后b>>=1 ,右移一位,进行下一轮操作

最后循环完毕,返回res

但这里还得注意几点:

  • 别忘了\(\mod m\)
  • 为防止越界,最好乘上1LL

所以res=res*a; a=a*a;得分别变成res=1LL*res*a%m; a=1LL*a*a%m;

所以,结束了?再放一遍程序吧


// a^b%m 模板
int qmi(int a,int b,int m){
    int res=1;
    while(b){
        if (b&1) res=1LL*res*a%m;  // b&1 等价于 b%2==1
        a=1LL*a*a%m;
        b>>=1;  // b/=2 
    }
    return res;
}

当然,根据需要,你也可以删去\(m\),即只是运算\(a^b\),或者把long long改为int,这里我推荐大家用long long(不开long long见祖宗,多年OI一场空)

posted @ 2020-10-05 22:36  不要学习szb  阅读(79)  评论(0)    收藏  举报