求快速冪(反覆平方法+快速冪算法)

例題:https://www.luogu.org/problemnew/show/P1226

反覆平方法板子(加取餘)

#include<iostream>
using namespace std;
typedef long long ll;
ll poww(ll a, ll b,ll n)
{
    ll d=1,t=a;
    while(b>0)
    {
        if(b%2==1) d=d*t%n;//b爲奇數時
        b=b/2;
        t=t*t%n;
    }
return d;
}
int main()
{
    ll a,b,c;
    cin>>a>>b>>c;
    printf("%lld^%lld mod %lld=%lld",a,b,c,poww(a,b,c));
}

快速冪

快速冪的目的就是做到快速求冪,假設我們要求a^b,按照樸素算法就是把a連乘b次,這樣一來時間複雜度是O(b)也即是O(n)級別,快速冪能做到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¹¹轉化爲算 a2^0*a2^1*a2^3,也就是a1*a2*a8 ,看出來快的多了吧原來算11次,現在算三次,但是這三項貌似不好求的樣子….不急,下面會有詳細解釋。   由於是二進制,很自然地想到用位運算這個強大的工具:&和>> &運算通常用於二進制取位操作,例如一個數 & 1 的結果就是取二進制的最末位。還可以判斷奇偶x&1==0爲偶,x&1==1爲奇。 >>運算比較單純,二進制去掉最後一位,不多說了,先放代碼

  int poww(int a, int b) {
    int ans = 1, base = a;
    while (b != 0) {
        if (b & 1 != 0)
            ans *= base;
            base *= base;
            b >>= 1;
    }
    return ans;
}

  以b==11爲例,b=>1011,二進制從右向左算,但乘出來的順序是 a^2^0×a^2^1=a^2^3,,是從左向右的。我們不斷的讓base*=base目的即是累乘,以便隨時對ans做出貢獻。
  其中要理解base*=base這一步:因爲base×base=base2 ,下一步再乘,就是base2×base2=base4 ,然後同理 base4×base4=base8 ,,由此可以做到base–>base2–>base4–>base8–>base16–>base32…….指數正是 2^i ,再看上面的例子,a¹¹= a1*a2*a8,這三項就可以完美解決了,快速冪就是這樣。
  由於指數函數是爆炸增長的函數,所以很有可能會超過int的範圍,根據題意選擇 long long還是mod某個數自己決定。
  

1. 遞歸寫法

LL pow_mod(LL a, LL b,int MOD)//a的b次方
{
    if(b == 0) 
        return 1;
    LL ret = pow_mod(a, b/2);
    ret = ret * ret % MOD;
    if(b % 2 == 1)
        ret = ret * a % MOD;
    return ret;
}

2. 遞推寫法

LL pow_mod(LL a, LL b,int MOD){//a的b次方
    LL ret = 1;
    while(b != 0)
    {
        if(b &1)
        {
            ret = (ret * a) % MOD ;
        }
        a = (a * a ) % MOD ;
        b>>=1   //b/= 2;
    }
    return ret;
 }

3. 二進制寫法(劃重點!)

LL pow_mod(LL a, LL b, LL MOD){//a的b次方求餘MOD
     LL ret = 1;
     while(b){
         if(b & 1) ret = (ret * a) % MOD;
         a = (a * a) % MOD;
         b >>= 1;
     }
     return ret;
 }
發佈了101 篇原創文章 · 獲贊 18 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章