浅谈 逆元乘法逆元
逆元
除以一個數再取模 = 乘以這個數的逆元再取模
設 inv[b] 是b的逆元,則(a/b) mod p = (a * inv[b]) mod p
(1)一個數的逆元是什么? ?一個數x在模p的條件下的逆元是多少
(2)一個數的逆元有無窮個,只求最小正整數即可
(3)一個數x在模p的條件下不一定有逆元,x關于p的逆元存在當且僅當x和p互質
推導:設 a 為 x 的逆元,b 為任意整數? ? ?//證明 x 與 p 必須互質
x * a?≡ 1 (mod p)
= x * a = 1 - b*p
= x * a +b * p = 1
若 x 與 p 不互質,則 x 和 p 存在公約數 d = gcd(x,p) >1
提取出 d ,得到:d*(x div d*a + p div d*b)=1
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(x div d*a + p div d*b)= 1 div d? ? ? ? ? ?//移項
易知x,p能整除 d ,所以括號內定為整數
又因為 d > 1,等式右邊必為真分數,等式無解
何為乘法逆元
對于兩個數 a,p,若gcd(a,p)=1 (即a,p互質),則一定存在另一數b,使得a*b?≡ 1(mod p) //上面已證
并稱此時的 b 為 a 關于 1 模 p 的乘法逆元,記 b 為 inv(a) 或 a^-1。
求逆元的方法
?
1.費馬小定理
當有兩個數 a,p 滿足gcd(a,p)=1時,則有 a^p ≡ a (mod p)
變形:a * a^(p-2)≡ 1(mod p)//和上面乘法逆元定義相似
所以,我們可以求出a^(p-2),即求出 a 的逆元。
當p比較大的時候需要用快速冪求解
復雜度O(logn)
const int mod = 1000000009; long long pow(long long a,long long b) {if(b<0)return 0;long long res=1;a%=mod;while(b)//快速冪{if(b & 1)res=(res*a)%mod;b >>= 1;a=(a*a)%mod;}return res; } long long inv(long long a)//求逆元 {return pow(a,mod-2);//求a^(mod-2) }2.拓展歐幾里得算法
由定義可知:a * b?≡ 1 (mod p)
等價于已知a,p求一個二元一次方程組 a*b = k*p+1
移項得:a*b - k*p = 1
然后套用求二元一次方程的方法,用擴展歐幾里得算法求得一組x0,y0和gcd?
檢查gcd是否為1?
gcd不為1則說明逆元不存在?
若為1,則調整x0到0~m-1的范圍中即可
PS:這種算法效率較高,常數較小,時間復雜度為O(ln n)
條件:可擴展歐幾里得求逆元 ab≡1(mod p)其中a,p互質
ll ecgcd(ll a,ll b,ll &x,ll &y) {if(b == 0)//終止條件{x = 1;y = 0;return a;}else {ll ans = ecgcd(b,a%b,x,y);//繼續遞歸下去ll temp = x;//暫且保存xx = y;y = y-a/b*temp;return ans;} } ll inv(ll a,ll n)//求逆元 {ll x,y;exgcd(a,n,x,y);//解二元一次方程組x = (x % n+n) % n;return x; }?
3.遞推計算階乘的逆元
當我們計算一大串連續的階乘的逆元時,采用費馬小定理或擴展歐幾里得就可能會時超,所以得采用一個更快的算法
令 f[i] = i!,可得:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? inv(f[i+1])≡ inv(f[i]*(i+1))? ? ? (mod p)
將(i+1)乘過去得:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? inv(f[i])≡ inv(f[i+1])* (i+1)? ? ? (mod p)
4.遞推計算連續的數的逆元:
當我們要計算連續的數的逆元時,我們可以采用一下遞推式:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
5.還有一種我也不知道的算法(盜的)
逆元打表法
有時會遇到這樣一種問題,在模質數p下,求1~n逆元 n< p(這里為奇質數)。可以O(n)求出所有逆元,有一個遞推式如下
?
???????????????????
?
它的推導過程如下,設,那么
?
???? ??
?
對上式兩邊同時除,進一步得到
?
???????
?
再把和替換掉,最終得到
?
???????
?
初始化,這樣就可以通過遞推法求出1->n模奇素數的所有逆元了。
還有一種???(不過好像就是我的第四種)
另外有個結論模的所有逆元值對應中所有的數,比如,那么對應的逆元是。
const int n=le5+5; int inv[n]; void inverse(int n,int p) {inv[1]=1;for(int i=2 ; i<=n ;i++){inv[i]=(ll)(p-p/i)*inv[p%i]%p;} }總結
- 上一篇: 嵌入式系统设计(五):详细介绍win8/
- 下一篇: python 移动平均线_Python