淺談乘法逆元
淺談乘法逆元
乘法逆元,一般用於求解\(\frac{A}{C}(mod ~ P)\)的值,因為我們通過模的定義可以知道上式顯然不等於\(\frac{A \% P}{B \% P}\)。例子有很多不再舉了。那麽如果我們要求上式大多數情況都需要借助逆元。
首先是定義:
若\(A \times X \equiv 1 (mod ~ P)\),並且\(A \perp P\)(\(\perp\):互質),那麽我們就稱\(X\)為\(A\)的逆元,簡稱為\(A^{- 1}\),也就是\(A\)在\(mod ~ P\)意義下的倒數。
借此我們可以知道\(\frac{A}{C}(mod ~ P)\)的求法:我們先求出\(C\)
擴展歐幾裏得版
首先從最簡單開始,就是一個擴展歐幾裏得,直接求解\(A \times X + P \times Y = 1\)就行了。
inline void Exgcd(int A, int P, int X, int Y) {
if (! B) X = 1, Y = 0 ;
else Exgcd(P, A % P, Y, X), Y -= A / B * X ;
}
這個方法雖然時間上比較慢,但是有一個優點,就是當\(A\)與\(P\)不互質的時候,依然可以適用。但是下面介紹的其他方法就必須滿足\(A \perp P\)
費馬小定理版
回顧一下費馬小定理的內容:
若\(A \perp P\), 則\(A^{P - 1} \equiv 1(mod ~ P)\)。
我們可以把它運用到乘法逆元裏。結合\(A \times X \equiv 1(mod ~ P)\)可以得到\(A \times X \equiv A^{P - 1}(mod ~ P)\)。當\(P\)為質數的時候,我們把左右都除以一個\(A\)可以得到\(X \equiv A^{P - 2}(mod P)\)。然後就可以一個快速冪求出來了。
inline void Fpm(int A, int P) { int Ans = 1 ; int M = P ; A %= M ; P -= 2 ; while (P) { if (P & 1) Ans = Ans * A % M ; A = A * A % M ; P >> = 1 ; } return Ans % M ; }
上面的復雜度是\(O(logN)\)的,在求多個逆元的時候可能\(O(NlogN)\)是過不去的。當然我們還有一種利用地推打出逆元表的方法做到\(O(N)\).
歐拉篩版
設\(INV[i]\)為\(i\)的逆元。我們知道有\(INV[A] = A ^ {P - 2}(mod ~ P),~INV[B] = B ^ {P - 2} (mod ~ P)\)
我們利用費馬小定理可以得\(INV[A \times B] = (AB) ^ {P - 2} (mod P)\)也就是說\(INV[A \times B] = INV[A] \times INV[B]\)。求得遞推式。我們就可以利用歐拉篩。
遞推版
為了方便起見就直接寫過程了。
設\(P = kA + r~~(r \in [0, P)~)\)。因為我們知道任何一個數都可以寫成這個形式嘛。
那麽有\(kA + r \equiv 0 (mod ~ P)\)
因為\(A^{P - 1} \equiv 1(mod ~ P)\)
所以\((kA +r) \times A^{- 1} \times r^{- 1} \equiv 0 (mod ~ P)\)
把左邊的括號拆開得\(kr^{- 1} + A^{- 1} \equiv 0 (mod ~ P)\)
移項:\(A^{- 1} \equiv -kr^{- 1}\)
在這裏我們知道\(k = \lfloor \frac{P}{A} \rfloor\)。
\(A^{- 1} \equiv -\lfloor \frac{P}{A} \rfloor \times r^{- 1}\)
並且我們還知道\(r ≤ A\)。那麽我們就可以借用數組\(INV[r]\)完成遞推。同時我們還知道\(r = P \% A\)
最後得到\(INV[A] = (P - \lfloor \frac{P}{A} \rfloor) \times INV[P\% A]\)
遞推完成,時間復雜度\(O(N)\)。
for (int i = 2 ; i <= N ; i ++)
INV[i] = P - (P / i) * INV[P % i] % P;
當然不要忘了初始化的問題。
淺談乘法逆元