浅谈gcd

gcd是数论的开始,也是数论的基础,

辗转相除法求最小公因数从小学起我们就已经知道是个什么了

但是为什么辗转相除法是对的呢?

它的时间复杂度是什么呢?

这些东西直到最近我才发现(应该是我比较菜吧QAQ)

首先证明gcd的正确性:

gcd(a,b)=gcd(b,a % b)(a>=b)

设gcd(a,b)=k,那么a=xk,b=yk

                         a/b=n.....r

                    xk  /  yk  = n.....r

                   n*yk + r   =xk

我们发现等式的右边存在k,则r一定是k的倍数

       gcd(yk,r)=k=gcd(a,b)

那么gcd的时间复杂度呢

(b,a%b)

a%b<=min(b,a%b)/2

a>=b时每次至少缩减一半

a<b时下次a>b

所以复杂度最多2log(max(a,b))

证明:a%b<=min(a,a%b)/2

a>b时 b<=a/那么a%b<b<=b<=a/2

a>b时 b>a/2 那么a%b=a-b<=a/2

a<b时 a%b=a

证毕

下面是gcd的代码

procedure gcd(a,b:longint);

begin

  if b=0 then exit(a)

 else gcd(b,a mod b);

end.

同时还有类题叫做类欧几里得算法

通过gcd的形式不断把问题缩小直到可以直接出解为止

(其实本人好像就碰到过一次吧)

 

 

emmm,gcd不仅仅可以求解两者的最小公因数,还可以用来求解不定方程(同余方程)

例如某年提高组的T1:同余方程

题目问的是满足 ax \mod b = 1axmodb=1 的最小正整数 xx。(a,ba,b是正整数)

但是不能暴力枚举 xx,会超时。

把问题转化一下,如果 ax \mod b = 1axmodb=1,那么 ax + by = 1ax+by=1,这里 yy 是我们新引入的某个整数,并且似乎是个负数才对。这样表示是为了用扩展欧几里得算法。我们将要努力求出一组 x,yx,y 来满足这个等式。稍微再等一下——

问题还需要转化。扩展欧几里得是用来求 ax + by = gcd(a,b)ax+by=gcd(a,b) 中的未知数的,怎么牵扯到等于 11 呢?

原理是,方程 ax + by = max+by=m 有解的必要条件是 m \mod gcd(a,b) = 0mmodgcd(a,b)=0。


这个简单证一下。

由最大公因数的定义,可知 aa 是 gcd(a,b)gcd(a,b) 的倍数,且 bb 是 gcd(a,b)gcd(a,b) 的倍数,

若 x,yx,y 都是整数,就确定了 ax + byax+by 是 gcd(a,b)gcd(a,b) 的倍数,

那么 mm 必须是 gcd(a,b)gcd(a,b) 的倍数,

那么 m \mod gcd(a,b) = 0mmodgcd(a,b)=0。


所以,方程 ax + by = 1ax+by=1 的有解的必要条件是 1 \mod gcd(a,b) = 01modgcd(a,b)=0。可怜的 gcd(a,b)gcd(a,b) 只能等于 11 了。这实际上就是 a,ba,b互质。

扩展欧几里得

前提是知道了普通欧几里得算法(辗转相除法)。下面字母挺多,希望你耐心地慢慢地读~

我们拿到了一组 a,ba,b。目标是求出满足 ax + by = gcd(a,b)ax+by=gcd(a,b) (①) 的 xx 与 yy。其中 xx 会成为答案,yy 是辅助答案。

(注意,虽然刚刚已经证明本题的 gcd(a,b)gcd(a,b) 必然等于 11,但是扩展欧几里得算法本身过程只能求 ax + by = gcd(a,b)ax+by=gcd(a,b) 的解。它正好非常适合本题,不过我们要按照它求解的过程去做)

根据普通欧几里得算法,gcd(a,b) = gcd(b, a\mod b)gcd(a,b)=gcd(b,amodb) (②)。

如果我们先前已经求出了另一组数 x_2, y_2x2,y2,它们满足 bx_2 + (a \mod b)y_2 = gcd(b, a \mod b)bx2+(amodb)y2=gcd(b,amodb) (③),(提示一下,这个等式与①的结构一致,系数则是根据②替换的。此处的递归形态已经有所显露,但还不着急)

结合②③,一定有

bx_2 + (a \mod b)y_2bx2+(amodb)y2

=gcd(b, a \mod b)=gcd(b,amodb)

=gcd(a,b)=gcd(a,b)

那么我们的目标变成了

求出满足 ax + by = bx_2 + (a \mod b)y2ax+by=bx2+(amodb)y2 (④)的 xx 与 yy。

其中a,b,x_2,y_2a,b,x2,y2 都已知,x,yx,y待求,未知数比方程更多,没有唯一解。我们先求出一组必然存在的解,最后将在答案处理时转变为使正整数 xx 最小的解。

取模运算是 a \mod b = a - b×(a/b)amodb=ab×(a/b),能理解吧?

等式④实际上是:

ax + by = bx_2 + (a-b×(a/b))y2ax+by=bx2+(ab×(a/b))y2

ax + by = bx_2 + ay2 - b × (a/b)y2ax+by=bx2+ay2b×(a/b)y2

ax + by = ay2 + b(x2-(a/b)y2)ax+by=ay2+b(x2(a/b)y2)

看上面这个,一组必然存在的解出现了!

x = y2, y = (x2 - (a/b)y2)x=y2,y=(x2(a/b)y2) ⑤

可见我们只要求出 x2,y2x2,y2,就能得出正确的x,yx,y。问题是 x2,y2x2,y2 怎么求。

脑海里抛掉前面的x,yx,y,现在我们手上是 b,a \mod bb,amodb 这两个系数,而目标是求出满足 bx_2 + (a \mod b)y_2 = gcd(b,a \mod b)bx2+(amodb)y2=gcd(b,amodb)(③)的 x_2x2 与 y_2y2,那么待会可以回馈给⑤。

等一下。

比较于③,我再去看看原方程①。

ax + by = gcd(a,b)ax+by=gcd(a,b) (①)

原方程中的 aa 变成了③中的 bb,原方程中的 bb 变成了③中的 a \mod bamodb 而已。

按照上面的一模一样下来(其实都是推导过程而已),我们发现,最好有 x_3,y_3x3,y3 来支撑 x_2, y_2x2,y2

再一模一样下来,我们又需要 x_4,y_4x4,y4 来支撑 x_3, y_3x3,y3

……

这个递归中 a,ba,b 不断变成 b, a \mod bb,amodb,逼近最后:

bb 将等于最早的 a,ba,b 的最大公因数,就像普通 gcdgcd 的结果。

但我们再往下一层。此时由于 a \mod b = 0amodb=0,下一层的 b = 0b=0。

是时候直接回馈了,我们需要一组 x_n,y_nxn,yn 满足 a_nx_n + b_ny_n = gcd(a_n,b_n)anxn+bnyn=gcd(an,bn)。

然而本层的 b_n = 0bn=0,则 gcd(a_n,b_n) = gcd(a_n,0) = a_ngcd(an,bn)=gcd(an,0)=an。那么等式左边取 x_n = 1, y_n = 0xn=1,yn=0,这个等式就妥妥的成立了。

最后一层回馈的 y_nyn 即使不是 00,等式一定也成立

代码在此

var
x1,x,y1,y,a,b:longint;
procedure exgcd(a1,b1:longint);
var t:longint;
begin
 if b1=0 then
    begin
      x:=1; y:=0;
    end
 else
   begin
     exgcd(b1,a1 mod b1);
     x1:=x; y1:=y;
     x:=y1; y:=x1-(a1 div b1)*y1;
   end;
end;
begin
 readln(a,b);
 exgcd(a,b);
 while x<0 do x:=x+b;
 writeln(x);
end.

  

转载于:https://www.cnblogs.com/by-w/p/9618718.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值