演算法學習筆記(2)快速冪
阿新 • • 發佈:2022-04-11
轉自演算法學習筆記(4):快速冪 - 知乎 (zhihu.com)
快速冪(Exponentiation by squaring,平方求冪)是一種簡單而有效的小演算法,它可以以的時間複雜度計算乘方。快速冪不僅本身非常常見,而且後續很多演算法也都會用到快速冪。
遞迴快速冪
剛剛我們用到的,無非是一個二分的思路。我們很自然地可以得到一個遞迴方程:
計算a的n次方,如果n是偶數(不為0),那麼就先計算a的n/2次方,然後平方;如果n是奇數,那麼就先計算a的n-1次方,再乘上a;遞迴出口是a的0次方為1。
遞迴快速冪的思路非常自然,程式碼也很簡單(直接把遞迴方程翻譯成程式碼即可):
int qpow(inta, 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)這個題可以拿來練手,既有快速冪又有取餘運算。