欧几里得算法 学习笔记

前言

本博客中所有的 有解 均指 有整数解
所有数如果不说明值域都是整数。

算法简介

为什么叫欧几里得算法呢?当然是欧几里得发明了啦
他能干什么呢?

  1. 求一个两个数字的最大公约数
  2. 求关于 \(x,y\) 的二元一次不定方程 \(ax+by=\gcd(a,b)\) 的整数解

求最大公约数(gcd)

最大公约数即为 \(\operatorname{Greatest Common Divisor}\),常缩写为 \(\gcd\)
一组数的公约数,是指同时是这组数中每一个数的约数的数。而最大公约数,则是指所有公约数里面最大的一个。
我们一般用 \(\gcd(a,b)\) 或者 \((a,b)\) 来表示两个数字的最大公约数。
我们一般用 \(\operatorname{lcm}(a,b)\) 或者 \([a,b]\) 来表示两个数字的最小公倍数(Least Common Multiple, LCM)。

显然 \(\gcd(a,b)=\gcd(b,a\bmod b)\)
证明如下:
\(a=bq+r\) 并且 \(0\le r<b\),显然 \(r=a \bmod b\)
\(d\mid a\)\(d\mid b\)\(d\) 就是 \(a,b\) 的公约数,
\(a=bq+r\)\(\dfrac{a}{d}=q\times\dfrac{b}{d}+\dfrac{r}{d}\)
也就是 \(\dfrac{r}{d}=\dfrac{a}{d}-q\times\dfrac{b}{d}\)
因为 \(d\mid a,d\mid b\),所以 \(\dfrac{a}{d},q\times \dfrac{b}{d}\) 都是整数,
所以 \(\dfrac{r}{d}\) 也是整数,\(d\) 也是 \(b,a \bmod b\) 的公约数,
同理我们也可以设 \(e\mid b\)\(e\mid a \bmod b\)
同理可以证明 \(e\) 也是 \(a,b\) 的公约数。
换句话说, \(a,b\) 的公约数都是 \(b,a \bmod b\) 的公约数,\(b,a \bmod b\) 的公约数也都是 \(a,b\) 的公约数,
也就是说 \(a,b\)\(b,a \bmod b\) 的公约数都相同,那么它们的最大公约数也都相等,也就是 \(\gcd(a,b)=\gcd(b,a\bmod b)\)
代码

int gcd(int x,int y){
	if(x%y==0) return y;
	return gcd(x%y,y);
}

从递归式不难得出复杂度为 \(O\left(\log_2\max(a,b)\right)\) ,并且当 \(a,b\) 为斐波那契数列的相邻两项的时候,算法复杂度最坏。
这种做法又称为辗转相除法。

同时我们也发现以下几个结论(这些结论证明显然,这里就不写证明过程了):

  1. \(\gcd(a,b,c)=\gcd\left(\gcd\left(a,b\right),c\right)\)
  2. \(\operatorname{lcm}(a,b)\times\gcd(a,b)=a\times b\)
  3. \(\operatorname{lcm}\left(a,b,c\right)= \operatorname{lcm}\left( \operatorname{lcm}\left(a,b\right) , c \right)\)
    这样我们就可以求出多个数的最大公约数以及单个数、多个数的最小公倍数了。

求二元一次不定方程的整数解(exgcd)

根据裴蜀定理,我们知道,关于 \(x,y\) 的二元一次不定方程 \(ax+by=\gcd(a,b)\) 有整数解。
证明略,我不会你自己看。
我们可以模仿计算最大公约数的方法来解这个方程。

假设有一个方程 \(ax_0+by_0=\gcd(a,b)\)
我们通过一次辗转相除,得到 \(bx_1+(a \bmod b)y_1=\gcd(a,b)\)
两式相减,得: \(ax_0+by_0-bx_1-(a \bmod b)y_1=0\)
又因为 \(a\bmod b=a-\lfloor\frac{a}{b}\rfloor\times b\)
所以 \(ax_0+by_0-bx_1-\left(a-\lfloor\frac{a}{b}\rfloor\right)\times by_1=0\)
展开得 \(ax_0+by_0-bx_1-ay_1+\lfloor\frac{a}{b}\rfloor\times by_1=0\)
化简得 \(a\left(x_0-y_1\right)+by_0-bx_1+\lfloor\frac{a}{b}\rfloor\times by_1=0\)
\(x_0=y_1,y_0=x_1-\lfloor\frac{a}{b}\rfloor\times y_1\)
递归边界就是 \(b=0\) ,此时返回 \(x=1,y=0\) 即可。
代码:

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

根据得到的两个解 \(x=x_0,y=y_0\) ,我们就可以得到这个方程的所有整数解:

\[x=x_0+\frac{kb}{\gcd(a,b)} \]

\[y=y_0-\frac{ka}{\gcd(a,b)} \]

显然这里的 \(k\) 是整数。

那么对于任意关于 \(x,y\) 方程 \(ax+by=c\) 该怎么解呢?
首先通过裴蜀定理判断它有没有解,如果有解那么肯定 \(\gcd(a,b)|c\) ,不妨设 \(c=n\gcd(a,b)\)
我们先解方程 \(ax+by=gcd(a,b)\) ,得到一个解 \(x=x_0,y=y_0\)
不难发现原方程也有一个解 \(x=nx_0,y=ny_0\)
解即为

\[x=nx_0+\frac{kb}{\gcd(a,b)} \]

\[y=ny_0-\frac{ka}{\gcd(a,b)} \]

复杂度和前面的一样,是 \(O\left(\log_2\max(a,b)\right)\).

应用

gcd除了求两个数字的最大公约数以外貌似我不知道其他功能,但是exgcd的功能非常强大。
这里只写我知道的吧...

  1. 求线性同余方程,因为 \(ax+by=c\) 等价于 \(ax\equiv c \pmod b\) ,这样可以得出在正整数范围内的 \(x\) 的最小值。
  2. 求逆元,因为 \(ax+by=1\) 等价于 \(ax\equiv 1 \pmod b\) ,由于存在逆元 \(a^{-1}\bmod b\) 所以 \(\gcd(a,b)=1\) ,也就是 \(ax+by=\gcd(a,b)\)
  3. exCRT会用到。
posted @ 2021-04-15 19:12  jiangtaizhe001  阅读(94)  评论(0编辑  收藏  举报