扩展欧几里得算法(exgcd)

前言

1

(gcd(a,b)=gcd(b,a\%b),(gcd(a,0)=a))

小证一下吧

(d=gcd(a,b))(a=d*k,b=d*k')

(a\%b!=0),则 (a\%b=a-leftlfloor dfrac ab ight floor * b = (k-leftlfloor dfrac ab ight floor*k')d) 并没有损失掉 (d)

(a\%b=0) 时,(b=gcd(a,b))

2

(a*x+b*y=c) 有解当且仅当 (gcd(a,b)|c)

这个就不多说了

exgcd

扩展欧几里得算法,求解出一组解 (x,y) 使得 (a*x+b*y=gcd(a,b))

我们当前有 (gcd(a,b)=gcd(b,a\%b),a\%b=a-leftlfloor dfrac ab ight floor * b)

(b) 代替 (a) , 用 (a\%b=a-leftlfloor dfrac ab ight floor * b) 代替 (b) 则原式成为

(b*x'+(a-leftlfloor dfrac ab ight floor * b)*y'=gcd(a,b)) 注意 (x' e x,y' e y)

我们大力化式子,差开 ((a-leftlfloor dfrac ab ight floor * b)*y)

原式变为

(b*x'+a*y'-b*leftlfloor dfrac ab ight floor*y'=gcd(a,b))

(a)(b) 放到一起

(a*y'+b*(x'-leftlfloor dfrac ab ight floor*y')=gcd(a,b))

因此我们得出 , (x=y',y=x'-leftlfloor dfrac ab ight floor*y')

当我们求出 (gcd(a,b))(b=0) 此时 (a*x+b*y=a) 我们让 (x=1,y=0) 即可

这样反向推回去就行了

放下代码吧

int exgcd(int a,int b,int &x,int &y){
	if(!b){ x=1,y=0; return a; }
	int gcd=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return gcd;
}

最后我们求得了 (a*x+b*y=gcd(a,b)) 如何求 (a*x+b*y=c) 呢?

(x,y) 分别乘上 (dfrac c{gcd(a,b)}) 就行了


现在我们已经求出了一组解 (x,y)如何得到另一组解 (x',y') 呢?

只需要让 (x'=x+dfrac{b}{gcd(a,b)},y'=y-dfrac{a}{gcd(a,b)}) 即可

证明

(x',y') 带入 (a*x+b*y=gcd(a,b)) 中 发现多出来的项消掉了

简单推导可知,这是 (x,y) 所能变动的最小范围


那么,我们知道了这个,就可以求出 (x) 的最小整数解,只需要让 (x\%dfrac b{gcd(a,b)}) 就行了

写公式好累啊,啊啊啊,就当复习了

原文地址:https://www.cnblogs.com/XiaoVsun/p/13054280.html