先说一下欧几里得算法是什么,就是小学学过的辗转相除法,用来求gcdgcd的。大概是像这样的:
int gcd(int a,int b)
{
if(b==0)
return a;
gcd(b,a%b);
}
然后我们在这段代码上加一些奇奇怪怪的东西,就变成扩展欧几里得了。顺便解释一下扩展欧几里得是什么,就是一种方法来求ax+by=gcd(a,b)ax+by=gcd(a,b),的特殊解的。相信大家想起来初中老师讲不定方程时的方法了吧。
没错,这就是扩欧。下面我们推一波公式:
假设我们已经求出了bx1+a%b∗y1=gcd(b,a%b)bx1+a%b∗y1=gcd(b,a%b),求ax+by=gcd(a,b)ax+by=gcd(a,b)。
因为gcd(a,b)=gcd(b,a%b)gcd(a,b)=gcd(b,a%b)
bx1+(a−⌊ab⌋∗b)y1=gcd(a,b)bx1+(a−⌊ab⌋∗b)y1=gcd(a,b)
ay1+b(x1−⌊ab⌋∗y1)=gcd(a,b)ay1+b(x1−⌊ab⌋∗y1)=gcd(a,b)
根据上面的对应
x=y1;y=x1−⌊ab⌋∗y1x=y1;y=x1−⌊ab⌋∗y1
ps:gcd(a,b)=gcd(b,a%b)gcd(a,b)=gcd(b,a%b)
而且我们知道了ax+0∗y=gcd(a,0)ax+0∗y=gcd(a,0)的解,所以可以使用exgcdexgcd求出ax+by=gcd(a,b)ax+by=gcd(a,b)的特殊解。
代码大概长这样:
int exgcd(int a,int b)
{
if(b==0)
{
x=1;
y=0;
return y;
}
gcd(b,a%b);
int t=y;
y=x-a/b*y;
x=t;
}
然后扩展欧几里得有一个比较有用的东西,就是求逆元。(a∗b)%mod=1(a∗b)%mod=1,则定义aa与互为逆元。现在我们知道bb,,求aa。
则
a∗b+y∗mod=1a∗b+y∗mod=1。
是不是和刚刚那个式子长得很像呀,是不是就可以用扩欧求了呀。
然后补充一波逆元的公式求法:
1、定义f(i)f(i)是ii在模下的逆元。f(i)=(−⌊modi⌋)∗f(mod%i)f(i)=(−⌊modi⌋)∗f(mod%i)
2、定义f(i)f(i)是i!i!在模modmod下的逆元。f(i)=f(i+1)∗(i+1)%modf(i)=f(i+1)∗(i+1)%mod
然后就是注意取模!!!