某王 课上给我们罗列一些算法,突然发现我竟然连扩欧都不会。。。
嗯,这篇博客不能被某王看到,不然要被打。。。
用途:
ax≡k*gcd(a,b) [mod b] 这种问题就可以用扩欧来解决。
核心思路:
用类似欧几里得算法(又名辗转相除法)转化成具有递推关系的式子来求解。
推导过程:
ax≡k*gcd(a,b) [mod b]很显然可以写成:ax-by=k*gcd(a,b),这里为了方便我们把它写成:ax+by=k*gcd(a,b)把y取个反就好了。
那么为什么这个方程保证有解呢?
我们另ax+by=m。
因为a%gcd(a,b)=0,b%gcd(a,b)=0,所以m%gcd(a,b)=0,所以m=k*gcd(a,b)是肯定有解的。
那么这个解应该怎么来求呢?
我们再写一个方程:b*x1+a%b*y1=k*gcd(b,a%b)=k*gcd(a,b)=a*x+b*y
继续转换:b*x1+(a-[a/b]下取整*b)*y1=a*x+b*y
再把a,b当作主元:a*y1+b*(x1-[a/b]下取整*y1)=a*x+b*y
得到:x=y1,y=x1-[a/b]下取整*y1。
让我们把b*x1+a%b*y1当成原方程再写一个方程:a%b*x2+b%(a%b)*y2=k*gcd(a%b,b%(a%b))=k*gcd(b,a%b)
那么我们是不是又能够得出:x1=y2,y1=x2-[a/b]下取整*y2。
我们是不是可以一直这样写下去直到b为0,这不就和欧几里得算法差不多。
最后一个方程就是:c*xn+0*yn=gcd(c,0)
因为gcd(c,0)=c,0*yn=0所以xn=0,而yn可以为任意值。(建议给yn取0,这样不容易爆long long)
然后我们再回上去求解就行。
代码实现:(这里以洛谷P1082为例)
var x,y,a,b,t:int64; procedure exgcd(a,b:int64); begin if b=0 then begin x:=1; y:=0; exit; end; exgcd(b,a mod b); t:=x; x:=y; y:=t-a div b*y; end; begin read(a,b); exgcd(a,b); x:=(x mod b+b)mod b; writeln(x); end.