OI 關於快速冪的簡單理解

2022-08-19 06:48:10 字數 2595 閱讀 4668

快速冪:因為a+b=c => n^a * n^b = n^c

所以n^m可以分解為n^m=n^a1 * n^a2 * n^a3... * n^ak ,a1+a2+a3...+ak=m

所以我們想到,如果存在k我們都知道二進位制轉十進位制時,是對每一位呈上位權,而計算機可以對十進位制數進行位運算,通過位運算可求出二進位制的每一位,。。。tobe continue

都知道算某個數的冪需要線性的複雜度,為了優化複雜度,就出現了所謂的快速冪。

快速冪的**很短,但是要原理需要一點心思。

首先,我們知道, 

a^b = a^c * a^d (c+d=b)

那麼,不就可以通過 a^b = a^b1 * a^b2 * a^b3... * a^bn (b1 + b2...+bn = b) 來快速獲得a^b嗎?這個方法的優越性在於,如果可以線性的求出a^b1~a^bn,不就是很快的演算法嗎?

因為a^b=a^c*a^d,c+d=b這條原理,我們的目標是找到普遍滿足 b = b1 + b2 ... + bn的規律。所以,我們必須要找出乙個統一的方法來確定b對應的b1~bn分別是多少。

如果各位知道進製轉換的原理,就可以知道:乙個n進製的數轉為十進位制等於 求和( i = 0~n-1 ) n ^ i * 第 i 位的數字。

例如,十進位制數10的二進位制數1010可以表示為: 2^0 * 0 + 2^1 * 1 + 2^2 * 0 + 2^3 * 1 (這裡挺繞的,為了方便理解和驗證,2^3*1意思是 2進製,第3位,二進位制數字1010中第三位是1)

仔細一想,這不就是我們要的"確定b對應的b1~bn分別是多少"嗎?這也是快速冪的原理所在,將乙個質數分解為許多可以線性乙個個求出的2的次方的冪。

我再次重申a^b=a^c*a^d,c+d=b這條原理,不能不搞清楚乘法和加法的關係,我們之前得到的加法規律實際上是應用於c+d=b這裡的,最後的計算還是要用乘法。

之前我一直在說,這個方法或者說規律的優越性在於我們可以線性的求出相加的每乙個指數。

說了這麼多廢話,目的在於接下來的這一條原理。

( a^(2^0) )^2 =   a^(2^1) 你可以親自驗證一下這條神奇的性質。不僅是對0+1 = 1有效,你可以把0換成任何乙個數,把1換成那個數+1,看看還會不會生效。       

對於每個數k,歸納一下,就是 (a^(2^k) )^2 = a^(2^(k+1) ) 。其實自己稍微一想,就明白是怎麼回事了。

在初中數學中,我們知道 (a^b)^k = a^(b*k)。   所以,(a^(2^k) )^2 = a^( (2^k)*2 )。而2^k = 相乘(i = 1~k) 2。(2*2*2*2...*2,k個2),所以(2^k)*2也就是「k個2相乘再乘2」不就是「k+1個2」,2^(k+1)麼。

總結一下完整的推導過程, (a^(2^k) )^2 = a^(2^k)*2 = a^(2^(k+1) )。

實際上這個推導非常簡單,寫出來是為了清晰思路,根據題意更好利用快速冪利用的性質。

最後剩下乙個點沒有說,那就是在二進位制中,每一位只有1和0兩種狀態,在0的時候看看我們之前的分析,實際上是沒有作用的(理解為指數相加時+0,或者相乘時乘1),為了不讓它「濫竽充數」地也來分一杯羹,我們使用&運算子,判斷這個二進位制最後一位是否為0,如果是0我們就不能在最後乘上它。當然,在看到**之前看這句話自然是一頭霧水,我們接下來看**:

typedef long long ll;

ll poww(ll a, ll b)//

a^b

return

re;}

解釋一下**。

b & 1代表著我們之前的判斷"為了不讓它「濫竽充數」地也來分一杯羹,我們使用&運算子,判斷這個二進位制最後一位是否為0"。為什麼要判斷「最後一位」,因為我們在判斷完指數的二進位制的某一位後,那一位不再有用,

所以我們使用 b >>= 1也就是位運算子「右移」來消除使用過的那一位。由於我們不想計算當前是哪一位,並且希望**盡可能的簡便高效,我們只能不計當前是多少位,

所以,為了簡潔高效地完成任務,實際上我們把原來的 乙個n進製的數轉為十進位制等於 "求和( i = 0~n-1 ) n ^ i * 第 i 位的數字」  變成了 「 求和( i = 0~n-1 ) n ^ i 」。

例如,十進位制數10的二進位制數1010按照我們原來的方式是: 2^0 * 0 + 2^1 * 1 + 2^2 * 0 + 2^3 * 1,而在**裡是 2^0  + 2^1  + 2^2  + 2^3 

這就不可避免的造成了在某個數的二進位制的某一位是0而造成本該是0的指數被我們計算成了別的數。所以,我們一定要在一開始加上二進位制下最後一位是否為0的條件,如果不是0那麼就可以把當前得到的結果乘到我們的最終結果變數上,如果是0則不能乘到最終結果變數上,但是a依然要平方,不能因為這一位數字的結果被忽略而不計下一位數字的結果應當按照我們之前的方法線性求出本當乘上的數字。(例如,按照我們之前1010的例子,2^0 * 0被我們忽略,但是如果上一位數字的結果被忽略就不考慮下一位的話,這一位的指數就是2^0*1了,與我們期待的結果不符。)

說了這麼多,發現自己想說的其實可以精煉一下,把自己的思考過程部分隱去。但是轉念一想,對於第一次聽說線性篩的oier或者別的學習者需要詳細的描述,而我自己也不能保證一直記住快速冪的原理,權當整理了。

如果本篇部落格有差錯或者不恰當之處,請多多指正。

OI 矩陣快速冪

經過漫長 並不務正業 的暑假,我終於回歸了oi。下面以此 為例子 luogu4910 include include typedef long long ll const ll mod 1000000007 ll fbi 5 5 ll fir 5 5 struct mat m m1 n n1 mat...

簡單的快速冪

題目大意 輸入b,p,k的值,求b p mod k的值。其中b,p,k k為長整型數。輸入輸出格式 輸入格式 三個整數b,p,k.輸出格式 輸出 b p mod k s s為運算結果 例如 輸入樣例 1 2 10 9 輸出樣例 1 2 10 mod 9 7 輸入樣例 2 4523 59 7762 輸...

簡單快速冪

對於求乙個數a的n次冪,我們第一想法就是呼叫包含在標頭檔案cmath或math.h標頭檔案下的pow a,n 函式,為了演算法看起來簡單用int代替大數模版。最簡單的實現就是用乙個迴圈和乙個變數,不斷用變數乘上底數,當然,這樣做的效率並不高o n include using namespace st...