情境引入
众所周知,有一个神奇的函数叫做gcd,中文名叫最大公约数
算法极其简单
int gcd(int a,int b){
if(!b)return a;
return gcd(b,a%b);
}
这种计算gcd的方法往往被称为辗转相除,但是,他的学名叫做“欧几里得算法”
但是,欧几里得这个数学家可只想用一个gcd来折磨人
于是,他又研究出一个叫做exgcd的东西,学名“扩展欧几里得”
例题: 洛谷 P1082同余方程
求关于x的方程a*x mod b = 1 的最小整数解
问题转化
我们观察题目这个等式,他的实质是在求ax+by=1这个等式的最小整数解
这里 y是我们新引入的某个整数,并且似乎是个负数才对。这样表示是为了用扩展欧几里得算法。我们将要努力求出一组 x,y 来满足这个等式。
看到这里,大家可能会有疑问:扩展欧几里得是用来求 ax + by = gcd(a,b) 中的未知数的,怎么牵扯到等于 1 呢?
原理是,方程 ax + by = max+by=m 有解的必要条件是 m mod gcd(a,b)=0。
由最大公因数的定义,可知 a 是 gcd(a,b) 的倍数,且 b是gcd(a,b) 的倍数,
若 x,y都是整数,就确定了 ax + by 是 gcd(a,b) 的倍数,
因为 m = ax + by,所以 m必须是 gcd(a,b) 的倍数,
那么 m mod gcd(a,b) = 0
可得出在这道题中,方程 ax + by = 1 的有解的必要条件是 1 mod gcd(a,b)=0。所以 gcd(a,b) 只能等于 1 了。这实际上就是a,b互质
扩展欧几里得
扩展欧几里得,简称扩欧,实在基础的欧几里得算法(gcd)的基础上实现的
代码:
# include <cstdio>
using namespace std;
int a,b,x,y,k;
void exgcd(int a,int b)
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b);
k=x;
x=y;
y=k-a/b*y;
return;
}
最后输出什么呢?
当然是x了,但是因为要mod一个数
所以我们要输出x%b
不对,再好好考虑考虑
x有可能是负数,所以我们要输出(x+b)%b
大功告成
小结
扩展欧几里得是一种非常常用的求逆元的方法
当然,你们有可能会问,你上面讲了这么多,和求逆元没什么关系啊
最后输出的就是逆元啊