[学习笔记] 扩展欧几里得算法

某王 课上给我们罗列一些算法,突然发现我竟然连扩欧都不会。。。

嗯,这篇博客不能被某王看到,不然要被打。。。

用途:

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.
posted @ 2018-11-07 16:49  WR_Eternity  阅读(174)  评论(0编辑  收藏  举报