快速冪取模和快乘取模
一、快速冪取模概念
快速冪取模,顧名思義,就是快速的求一個冪式的模(余),比如a^b%c,快速的計算出這個式子的值。
在程序設計過程中,經常要去求一些大數對於某個數的余數,為了得到更快、計算範圍更大的算法,產生了快速冪取模算法。
二、快速冪取模算法實現
1)很容易能想到,循環b次,每次乘a,最後對c取余就可以了。
int ans = 1; for(int i = 1; i<=b; i++) { ans = ans * a; } ans = ans % c;
這個樸素算法的問題是:
1.如果a和b都很大,那麽ans很有可能超出long long類型,最後結果錯誤
2.如果b很大,這樣計算會超時。
所以對這個算法需要改進
2)有一個很簡單的公式如下:
證明略,由上面公式我們可以對上面算法進行優化
int ans = 1; a = a % c; for(int i = 1; i<=b; i++) { ans = (ans * a) % c;//這裏再取了一次余 } ans = ans % c;
這樣就解決了超出long long的問題了,但是時間復雜度還沒有降低。
3)為了解決超時問題,我們可以使用下面的公式,證明略
int ans = 1; a = a % c; if(b%2==1) ans= (ans * a) mod c; //如果是奇數,要多求一步,可以提前算到ans中 k = (a*a) % c; //我們取a2而不是a for(int i = 1; i<=b/2; i++) { ans = (ans * k) % c; } ans = ans % c;
這樣,我們就把時間復雜度降到b/2了,觀察上式子,可以發現,當我們令k = (a * a) mod c時,狀態已經發生了變化,我們所要求的最終結果即為(k)^b/2 mod c而不是原來的a^b mod c,當下次求(k)^b/2 mod c時,我們可以繼續對這個式子記成上面格式,我們發現這個過程是可以重復下去的。
4)最終我們得到快速冪取模的算法
int ans = 1; a = a % c; while(b>0) { if(b % 2 == 1) ans = (ans * a) % c; b = b/2; a = (a * a) % c; }
三、快速冪取模模板
int PowerMod(int a, int b, int c)//a^b%c { int ans = 1; a = a % c; while(b>0) { if(b % 2 = = 1) ans = (ans * a) % c; b = b/2; a = (a * a) % c; } return ans; }
四、快乘取模
1.概念:
快速乘法是求兩個數相乘,即求解a*b%c,很明顯這個不會超時,但是如果當a和b特別大的時候,兩個數相乘可能超過long long 範圍,所以要使用快速乘法,因為在加法運算的時候不會超,而且可以直接取模,這樣就會保證數據超不了了。快速乘法的思想和快速冪的思想一樣,快速冪是求一個數的高次冪,快速乘法是求兩個數相乘。
2.算法實現:
這樣的式子和a^b%c很像,所以可以用類似於快速冪取模的方法來做。即,將b寫成二進制來看,然後拆開相加(正因為二進制的特殊性,才有快速乘和快速冪的成功),比如下面的例子:
32+16+4=52 (實際操作過程中,每次相加都取模)
這一過程和快速冪取模非常相似。
3.模板:
int multiMod(int a, int b, int c) { int ans = 0;//註意初始化是0,不是1 while (b) { if (b & 1) ans=(ans+a)%c; a = (a + a) % c;//和快速冪一樣,只不過這裏是加 b >>= 1; } return ans; }
快速冪取模和快乘取模