1. 程式人生 > 其它 >關於 exgcd求逆元 我的理解

關於 exgcd求逆元 我的理解

筆者蒟蒻一隻,如有錯誤和不準確不嚴謹的地方望指正 orz

逆元

我們有時會在求概率等或答案為分數的題目中遇到求逆元的情況

模板->航電 hd-1576

遇到了求\(\bf{\frac{A}{B}}\)mod P 的問題

題目保證B和P互質

給出 n (A mod P 的值) 、BP

我們知道

\[(A+B) mod P = \big((A mod P)+(B mod P)\big)mod P \]\[(A-B) mod P = \big((A mod P)-(B mod P)\big)mod P \]\[(A\times B) mod P = \big((A mod P)\times (B mod P)\big)mod P \]

但是

\[(A \div B) mod P \neq \big((AmodP)\div (BmodP)\big)mod P \]

那該怎麼辦呢

我們可以想辦法將它化成乘法形式 滿足上面的第三個公式

學過倒數,我們想到了

\[(A \div B)mod P=(\frac{A}{B})mod P=(A\times B^{-1})mod P \]

那麼,由上述的關於乘方取餘數的式子得到

\[(A\times B^{-1}) mod P = \big((A mod P)\times (B^{-1} mod P) \big)mod P \]

由題目得 A mod P 的值為 n

之後題目就轉化成了 求 \(\frac{1}{B}\)

​mod P 的值

問題又來了 \(\frac{1}{B}\) 的值該怎麼求呢

它滿足

\[(B\times B^{-1}) mod P=1 \]

所以定義 \(\frac{1}{B}\) 叫做B關於P的逆(B也是 \(\frac{1}{B}\) 關於P的逆元

可以表示為

\[B\equiv B^{-1}(mod\;P) \]

繼續進行式子的變形 上上一個式子等價於

\[B\times B^{-1}=1+k\times P\qquad k\ge0 \]\[B\times B^{-1}-k\times P=1\qquad k\ge0 \]

到此就用到了擴充套件歐幾里得 exgcd

\[擴充套件歐幾里得:給予二整數 a 與 b, 必存在有整數 x 與 y 使得ax + by = gcd(a,b) \]

這裡使用exgcd就求出來 B 的逆元

接著返回題目中 用 B的逆元n 再對 P 取模就可了

擴充套件歐幾里得 exgcd

\[ax+by=gcd(a,b) \]\[ax+by=gcd(b,a\,mod\,b) \]\[ax+by=bx_{0}+(a\,mod\,b)y_{0} \]\[ax+by=bx_{0}+(a-(\lfloor {\frac {a} {b}}\rfloor\times b)y_{0} \]\[ax+by=bx_{0}+ay_{0}-\lfloor {\frac {a} {b}}\rfloor\times by_{0} \]\[ax+by=ay_{0}+b(x_{0}-\lfloor {\frac {a} {b}}\rfloor\times y_{0}) \]

通過這一波轉化就可以把公式遞迴下去了

code

exgcd:

ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){x=1;y=0;return a;}
	ll tx=x,ty=y;
	ll g=exgcd(b,a%b,tx,ty);
	ll t=x;
	x=ty;
	y=tx-(a/b)*ty;
}

求逆元 (求 n 關於 m 的逆元):

ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1,y=0;
        return a;
    }
    ll r = exgcd(b,a%b,x,y);
    ll t = x;
        x = y;
        y = t - a/b*y;
    return r;
}
ll inv(ll n,ll m){
    ll x,y;
    ll ans = exgcd(n,m,x,y);
    if(ans == 1)
        return (x%m+m)%m;
		else
        return -1;
}

hd-1576:

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1,y=0;
        return a;
    }
    ll r = exgcd(b,a%b,x,y);
    ll t = x;
        x = y;
        y = t - a/b*y;
    return r;
}
ll inv(ll n,ll m){
    ll x,y;
    ll ans = exgcd(n,m,x,y);
    if(ans == 1)
        return (x%m+m)%m;
		else
        return -1;
}
int main(){
    ll n,m;
	ll t;
	cin>>t;
	while(t--){
		cin>>n>>m;
		ll ans = inv(m,9973);
		cout<<(n*ans)%9973<<endl;
	}
	return 0;
}