1. 程式人生 > >HRBU-ACM 數論1-快速冪

HRBU-ACM 數論1-快速冪

快速冪取模的用途:在ACM這類競賽中,可能會遇到指數型的資料取模問題,這個時候如果直接用int或者long long儲存,就

有可能會超出計算機整數的存取範圍,而導致資料出錯。所以我們需要一種方法進行計算。而這種方法就是我們這次要講到

的快速冪取模(簡稱快速冪)。這種演算法在時間和空間上都做了儘可能的優化,所以學會之後,會覺得非常好用。


快速冪取模的思路:快速冪實現的最基本的理論就是我們離散課上或者數論中學過的一條公式推出的引理。

引理:積的取餘等於取餘的積的取餘。

再在這條引理的基礎之上,對指數型資料進行拆分以及合併,從而得到我們用的快速冪演算法。


本文我就不用例題講解,直接對快速冪進行解析。畢竟快速冪的演算法相對簡單,而且適用題型較為一致。


快速冪具體分析:對a^b進行分析。

對於當a和b較小是直接用int或者long存是沒有問題的,但是當a和b大到一定程度時,這就不是暴力存就

可以解決的問題了。我們應該怎麼去解決這個問題呢?


在這裡我們需要把注意力放在“大”字上面,正是由於a和b過大才導致的問題。所以我們要想辦法不斷地減

小a和b的規模,所謂逐個擊破。

根據上面的那條引理,我們知道了可以把指數拆開,從這個突破口突破。這裡我們就不難想到這樣一個演算法:
 

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL p=100007;
LL pow_mod(LL a, LL b, LL p){//a的b次方求餘p
    //引理:積的取餘等於取餘的積的取餘。
    /*LL ret =1;
    while(b--)
    {
        ret*=a;
    }
    return ret;
    */
    /**
    a^11=a^(2^0+2^1+2^3)
    11的二進位制 1011
    11=2^3*1+2^2*0+2^1*1+2^0*1;
    a^11=a^(2^0)*a^(2^1)*a^(2^3)
    **/
    LL ret = 1;
    while(b){
        if(b & 1) ret = (ret * a) % p;///b&1 當b=1時b&1=1 其餘皆為0
        a = (a * a) % p;
        b>>=1;
    }
    return ret;
}
LL mul(LL a, LL b, LL p){//快速乘,計算a*b%p
    LL ret = 0;
    while(b){
        if(b & 1) ret = (ret + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return ret;
}
int main()
{
    LL a,b;
    cin>>a>>b;
    //b>>=1;
   // cout<<b<<endl;
    cout<<pow_mod(a,b,p)<<endl;
    cout<<mul(a,b,p)<<endl;
    return 0;
}