扩展欧几里得(exgcd)求逆元『蒟蒻笔记』

笔者蒟蒻一只,如有错误和不准确不严谨的地方望指正 orz

逆元

我们有时会在求概率等或答案为分数的题目中遇到求逆元的情况

模板->航电 hd-1576

遇到了求\(\bf{\frac{A}{B}}\)​mod \(P\) 的问题

题目保证 \(B\)\(P\) 互质

给出 \(n\)​ (\(AmodP\)​的值) 、\(B\)​​ 、\(P\)

我们知道

\[(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 \]

由题目得 \(Amod 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}) mod P=1\)等价于

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

到此就用到了扩展欧几里得 exgcd

\[扩展欧几里得:给予二整数 a 与 b, 必存在有整数 x 与 y 使得ax + by = gcd(a,b) \]

这里使用exgcd就求出来 \(B\)​ 的逆元 了

接着返回题目中 用 \(B\)​​ 的逆元 乘 \(n\)​​​ 再对 \(P\)​​​ 取模就可了

扩展欧几里得 exgcd

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

通过这一波转化,\(y_0\) 就变成了新的\(x\) , \((x_0-\lfloor\frac{a}{b}\rfloor\times y_0)\)就变成了新的 \(y\) ,继续套用exgcd,可以把公式递归下去了,\(b=0\) 时的 \(a\) 就是结果

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;
}
posted @ 2021-08-04 12:20  莳曳  阅读(430)  评论(0)    收藏  举报