乘法逆元的几种计算方法
乘法逆元是數論中重要的內容,也是 ACM 中常用到的數論算法之一。所以,如何高效的求出乘法逆元是一個值得研究的問題。
這里我們只討論當模數為素數的情況,因為如果模數不為素數,則不一定每個數都有逆元。
定義
在 ?mod p的意義下我們把?xx?的乘法逆元寫作?x ^ {-1}x??1??。
乘法逆元有如下的性質:
乘法逆元的一大應用是模意義下的除法,除法在模意義下并不是封閉的,但我們可以根據上述公式,將其轉化為乘法。
費馬小定理
要求?pp?為素數。
上述公式可變形為
由乘法逆元的定義,a ^ {p - 2}a?p?2???即為?aa?的乘法逆元。
使用快速冪計算?a ^ {p - 2}a?p?2??,總時間復雜度為?O(\log a)O(loga)。
代碼
inline int pow(const int n, const int k) {long long ans = 1;for (long long num = n, t = k; t; num = num * num % MOD, t >>= 1) if (t & 1) ans = ans * num % MOD;return ans; } inline int inv(const int num) {return pow(num, MOD - 2); }擴展歐幾里得
擴展歐幾里得(EXGCD)算法可以在?O(\log \max(a, b))O(logmax(a,b))?的時間內求出關于?xx、yy?的方程
的一組整數解
當?bb?為素數時,\gcd(a, b) = 1gcd(a,b)=1,此時有
時間復雜度為?O(\log a)O(loga)。
代碼
void exgcd(const int a, const int b, int &g, int &x, int &y) {if (!b) g = a, x = 1, y = 0;else exgcd(b, a % b, g, y, x), y -= x * (a / b); } inline int inv(const int num) {int g, x, y;exgcd(num, MOD, g, x, y);return ((x % MOD) + MOD) % MOD; }遞推法
代碼
inv[1] = 1; for (int i = 2; i <= MAXN; i++) inv[i] = ((-(MOD / i) * inv[MOD % i]) % MOD + MOD) % MOD;下面是ACdreamers關于遞推求解逆元的推導過程(個人覺得他的更好)
其實有些題需要用到模的所有逆元,這里為奇質數。那么如果用快速冪求時間復雜度為,
如果對于一個1000000級別的素數,這樣做的時間復雜度是很高了。實際上有的算法,有一個遞推式如下
?
???????????????????
?
它的推導過程如下,設,那么
?
???? ??
?
對上式兩邊同時除,進一步得到
?
???????
?
再把和替換掉,最終得到
?
???????
?
初始化,這樣就可以通過遞推法求出模奇素數的所有逆元了。
?
另外模的所有逆元值對應中所有的數,比如,那么對應的逆元是。
總結
以上是生活随笔為你收集整理的乘法逆元的几种计算方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jquery在两个HTM页面之间跳转传递
- 下一篇: 【poi第五节】poi设置Excel单元