刘汝佳の扩展欧几里得算法详解

直线上的点

求直线 a x + b y + c = 0 ax+by+c=0 ax+by+c=0上有多少个整点 ( x , y ) (x,y) (x,y)满足 x ∈ [ x 1 , x 2 ] , y ∈ [ y 1 , y 2 ] x\in[x1,x2],y\in[y1,y2] x[x1,x2],y[y1,y2]

扩展欧几里得算法

在解决引中的问题之前,我们需要学习一下扩展欧几里得算法——找出一对整数对 ( x , y ) (x,y) (x,y)使其满足 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)

  • 注:x,y不一定是整数

例: a = 6 , b = 15 , g c d ( a , b ) = 3 , 6 ∗ 3 − 15 ∗ 1 = 3 a=6,b=15,gcd(a,b)=3,6*3-15*1=3 a=6,b=15,gcd(a,b)=3,63151=3,其中 x = 3 , y = − 1 x=3,y=-1 x=3,y=1且有其他解存在

核心程序

下面是刘汝佳sama的代码

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

首先,扩展欧几里得算法是通过递归求解的,那么怎么进入下一层递归呢?

证明①

a x + b y = d , a = t b + r ( a > = b ) ax+by=d,a=tb+r(a>=b) ax+by=d,a=tb+r(a>=b)
其中 t = ⌊ a b ⌋ , r = a % b t={\lfloor {a\over b}\rfloor},r=a\%b t=ba,r=a%b
代入得 t b x + r x + b y = d tbx+rx+by=d tbx+rx+by=d
整理得 b ( t x + y ) + r x = d b(tx+y)+rx=d b(tx+y)+rx=d
惊奇的发现,式子化成了 a x + b y = d ax+by=d ax+by=d的形式
那么此时我们设当前层的 x , y x,y x,y x n o w , y n o w x_{now},y_{now} xnow,ynow
下一层的 x , y x,y x,y x n e x t , y n e x t x_{next},y_{next} xnext,ynext
由此可得 x n e x t = t x n o w + y n o w , y n e x t = x n o w x_{next}=tx_{now}+y_{now},y_{next}=x_{now} xnext=txnow+ynow,ynext=xnow
同时,下一层的 a , b a,b a,b也确定了
a n e x t = b n o w , b n e x t = a n o w % b n o w a_{next}=b_{now},b_{next}=a_{now}\%b_{now} anext=bnow,bnext=anow%bnow
由下至上求解,所以当前层在取用上一层递归的时候需要一点操作
先求当前层的x,根据上面推出的公式不难得出 x n o w = y n e x t x_{now}=y_{next} xnow=ynext
在求y时,我们先让y等于上一层的x,再减去上一层的 x ∗ ⌊ a b ⌋ x*{\lfloor{a\over b}\rfloor} xba就是y啦( y n o w = x n e x t − t x n o w y_{now}=x_{next}-tx_{now} ynow=xnexttxnow)
因为是递归求解,那么终止条件是什么呢?
不难看出,当 b = 0 b=0 b=0时, g c d ( a , 0 ) = a ∗ 1 − 0 ∗ 0 = a gcd(a,0)=a*1-0*0=a gcd(a,0)=a100=a,此时 x = 1 , y = 0 x=1,y=0 x=1,y=0

改写程序

刘汝佳的代码真是太好理解啦,所以我写一个难理解的

pair<int,int> exgcd(int a,int b,int &d){//返回的是x,y
	if(!b) { d=a;return make_pair(1,0); }
	auto [y,x]=exgcd(b,a%b,d);
	return make_pair(x,y-x*(a/b));//注意这里不用反过来
}

证明②

上面求出了一组解 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),那么其他解呢?
另取任意一组解 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)
则有 a x 1 + b y 1 = a x 2 + b y 2 ax_1+by_1=ax_2+by_2 ax1+by1=ax2+by2,变形得 a ( x 1 − x 2 ) = b ( y 2 − y 1 ) a(x_1-x_2)=b(y_2-y_1) a(x1x2)=b(y2y1)
g c d ( a , b ) = g gcd(a,b)=g gcd(a,b)=g,那么让两遍都除以g,得 a ′ ( x 1 − x 2 ) = b ′ ( y 2 − y 1 ) ( a ′ 与 b ′ 互质 ) a'(x_1-x_2)=b'(y_2-y_1)(a'与b'互质) a(x1x2)=b(y2y1)(ab互质)
因此 ( x 1 − x 2 ) (x_1-x_2) (x1x2)一定是 b ′ b' b的整数倍,为什么呢?
a ′ ( x 1 − x 2 ) b ′ = y 2 − y 1 {a'(x_1-x_2)\over b'}=y_2-y_1 ba(x1x2)=y2y1因为 a ′ , b ′ a',b' a,b互质,所以 x 1 − x 2 x_1-x_2 x1x2可以将 b ′ b' b约去来得到整数 y 2 − y 1 y_2-y_1 y2y1
x 1 − x 2 = k b ′ x_1-x_2=kb' x1x2=kb,得 y 2 − y 1 = k a ′ y_2-y_1=ka' y2y1=ka
所以,若方程 a x + b y = c ax+by=c ax+by=c的一组解为 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)
那么其他任意解均可写成 ( x 0 + k b ′ , y 0 − k b ′ ) (x_0+kb',y_0-kb') (x0+kb,y0kb)
有了这个结论,移项得 a x + b y = − c ax+by=-c ax+by=c然后求出一组解即可

证明③

  • 例1: 6 x + 15 y = 9 6x+15y=9 6x+15y=9,得知 g c d ( 6 , 15 ) = 3 gcd(6,15)=3 gcd(6,15)=3并求出一组解 ( − 2 , 1 ) ( 6 x + 15 y = g c d ( 6 , 15 ) 情况下 ) (-2,1)(6x+15y=gcd(6,15)情况下) (2,1)(6x+15y=gcd(6,15)情况下)后,只需要左右乘3就可以得到答案,也就是说答案为 ( − 6 , 3 ) (-6,3) (6,3)
  • 例2: 6 x + 15 y = 8 6x+15y=8 6x+15y=8,当像例1一样求出一组解 ( − 2 , 1 ) (-2,1) (2,1)后,发现无论如何变动都无法使等号右边成为8,除非出现约数,显然是无解的

由此可得: g = g c d ( a , b ) , a x + b y = g g=gcd(a,b),ax+by=g g=gcd(a,b),ax+by=g的一组解为 ( x 0 , y 0 ) (x_0,y_0) (x0,y0),当c为g的整数倍数时存在解 ( x 0 c / g , y 0 c / g ) (x_0c/g,y_0c/g) (x0c/g,y0c/g),否则无解

end

至此才算是完整解决了引中的问题
所以,感谢刘的讲解
完结撒花

你可能感兴趣的:(算法,c++,刘汝佳,数论)