1. 程式人生 > 其它 >演算法學習筆記(2)快速冪

演算法學習筆記(2)快速冪

轉自演算法學習筆記(4):快速冪 - 知乎 (zhihu.com)

快速冪(Exponentiation by squaring,平方求冪)是一種簡單而有效的小演算法,它可以以的時間複雜度計算乘方。快速冪不僅本身非常常見,而且後續很多演算法也都會用到快速冪。

遞迴快速冪

剛剛我們用到的,無非是一個二分的思路。我們很自然地可以得到一個遞迴方程:

計算a的n次方,如果n是偶數(不為0),那麼就先計算a的n/2次方,然後平方;如果n是奇數,那麼就先計算a的n-1次方,再乘上a;遞迴出口是a的0次方為1。

遞迴快速冪的思路非常自然,程式碼也很簡單(直接把遞迴方程翻譯成程式碼即可):

int qpow(int
a, int n) { if (n == 0) return 1; else if (n % 2 == 1) return qpow(a, n - 1) * a; else { int temp = qpow(a, n / 2); return temp * temp; } }

在實際問題中,題目常常會要求對一個大素數取模,這是因為計算結果可能會非常巨大,但是在這裡考察高精度又沒有必要。這時我們的快速冪也應當進行取模,此時應當注意,原則是步步取模,如果MOD較大,還應當開long long。這個還是很常用的。

//遞迴快速冪(對大素數取模)
#define MOD 1000000007
typedef long long ll;
ll qpow(ll a, ll n)
{
    if (n == 0)
        return 1;
    else if (n % 2 == 1)
        return qpow(a, n - 1) * a % MOD;
    else
    {
        ll temp = qpow(a, n / 2) % MOD;
        return temp * temp % MOD;
    }
}

非遞迴快速冪

我們換一個角度來引入非遞迴的快速冪。還是7的10次方,但這次,我們把10寫成二進位制的形式,也就是  。

現在我們要計算  ,可以怎麼做?我們很自然地想到可以把它拆分為  . 實際上,對於任意的整數,我們都可以把它拆成若干個  的形式相乘。而這些,恰好就是  、、……我們只需不斷把底數平方就可以算出它們。

我們先看程式碼,再來仔細推敲這個過程:

//非遞迴快速冪
int qpow(int a, int n){
    int ans = 1;
    while(n){
        if(n&1)        //如果n的當前末位為1
            ans *= a;  //ans乘上當前的a
        a *= a;        //a自乘
        n >>= 1;       //n往右移一位
    }
    return ans;
}

P1226 【模板】快速冪||取餘運算 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)這個題可以拿來練手,既有快速冪又有取餘運算。