最大公约数
最大公约数即为 Greatest Common Divisor,常缩写为 gcd。
一组整数的公约数,是指同时是这组数中每一个数的约数的数。 ± 1 \pm 1 ±1 是任意一组整数的公约数。
一组整数的最大公约数,是指所有公约数里面最大的一个。
如果两个数 a a a 和 b b b 满足 gcd ( a , b ) = 1 \gcd(a, b) = 1 gcd(a,b)=1,我们称 a a a 和 b b b 互质。
那么如何求最大公约数呢?我们先考虑两个数的情况。
欧几里得算法(辗转相除法)
如果我们已知两个数 a a a 和 b b b,如何求出二者的最大公约数呢?
不妨设 a > b a > b a>b
我们发现如果 b b b 是 a a a 的约数,那么 b b b 就是二者的最大公约数。
下面讨论不能整除的情况,即 a = b × q + r a = b \times q + r a=b×q+r,其中 r < b r < b r<b。
我们通过证明可以得到 gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a \bmod b) gcd(a,b)=gcd(b,amodb)
- 证明
设 a = b k + c a=bk+c a=bk+c,显然有 c = a m o d b c=a \bmod b c=amodb。设 d ∣ a , d ∣ b d \mid a,~d \mid b d∣a, d∣b,则 c = a − b k , c d = a d − b d k c=a-bk, \frac{c}{d}=\frac{a}{d}-\frac{b}{d}k c=a−bk,dc=da−dbk。
由右边的式子可知 c d \frac{c}{d} dc 为整数,即 d ∣ c d \mid c d∣c 所以对于 a , b a,b a,b 的公约数,它也会是 a m o d b a \bmod b amodb 的公约数。
反过来也需要证明:
设 d ∣ b , ∣ ( a m o d b ) d \mid b,~\mid (a \bmod b) d∣b, ∣(amodb),我们还是可以像之前一样得到以下式子 a m o d b d = a d − b d k , a m o d b d + b d k = a d \frac{a\bmod b}{d}=\frac{a}{d}-\frac{b}{d}k,~\frac{a\bmod b}{d}+\frac{b}{d}k=\frac{a}{d} damodb=da−dbk, damodb+dbk=da。
因为左边式子显然为整数,所以 a d \frac{a}{d} da 也为整数,即 d ∣ a d \mid a d∣a,所以 b , a m o d b b,a\bmod b b,amodb 的公约数也是 a , b a,b a,b 的公约数。
既然两式公约数都是相同的,那么最大公约数也会相同。
所以得到式子 gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a\bmod b) gcd(a,b)=gcd(b,amodb)
既然得到了 gcd ( a , b ) = gcd ( b , r ) \gcd(a, b) = \gcd(b, r) gcd(a,b)=gcd(b,r),这里两个数的大小是不会增大的,那么我们也就得到了关于两个数的最大公约数的一个递归求法。
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
递归至 b==0
(即上一步的 a%b==0
) 的情况再返回值即可。
上述算法被称作欧几里得算法(Euclidean algorithm)。
欧几里得算法的时间效率如何呢?下面我们证明,欧几里得算法的时间复杂度为 O ( log n ) O(\log n) O(logn)。
当我们求 gcd ( a , b ) \gcd(a,b) gcd(a,b) 的时候,会遇到两种情况:
- a < b a < b a<b,这时候 gcd ( a , b ) = gcd ( b , a ) \gcd(a,b)=\gcd(b,a) gcd(a,b)=gcd(b,a);
- a ≥ b a \geq b a≥b,这时候 gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a \bmod b) gcd(a,b)=gcd(b,amodb),而对 a a a 取模会让 a a a 至少折半。这意味着这一过程最多发生 O ( log n ) O(\log n) O(logn) 次。
第一种情况发生后一定会发生第二种情况,因此第一种情况的发生次数一定 不多于 第二种情况的发生次数。
从而我们最多递归 O ( log n ) O(\log n) O(logn) 次就可以得出结果。
多个数的最大公约数
那怎么求多个数的最大公约数呢?显然答案一定是每个数的约数,那么也一定是每相邻两个数的约数。我们采用归纳法,可以证明,每次取出两个数求出答案后再放回去,不会对所需要的答案造成影响。
扩展欧几里得算法
扩展欧几里得算法(Extended Euclidean algorithm, EXGCD),常用于求 a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b) 的一组可行解。
- 证明
设
a x 1 + b y 1 = gcd ( a , b ) ax_1+by_1=\gcd(a,b) ax1+by1=gcd(a,b)
b x 2 + ( a m o d b ) y 2 = gcd ( b , a m o d b ) bx_2+(a\bmod b)y_2=\gcd(b,a\bmod b) bx2+(amodb)y2=gcd(b,amodb)
由欧几里得定理可知: gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a\bmod b) gcd(a,b)=gcd(b,amodb)
所以 a x 1 + b y 1 = b x 2 + ( a m o d b ) y 2 ax_1+by_1=bx_2+(a\bmod b)y_2 ax1+by1=bx2+(amodb)y2
又因为 a m o d b = a − ( ⌊ a b ⌋ × b ) a\bmod b=a-(\lfloor\frac{a}{b}\rfloor\times b) amodb=a−(⌊ba⌋×b)
所以 a x 1 + b y 1 = b x 2 + ( a − ( ⌊ a b ⌋ × b ) ) y 2 ax_1+by_1=bx_2+(a-(\lfloor\frac{a}{b}\rfloor\times b))y_2 ax1+by1=bx2+(a−(⌊ba⌋×b))y2
a x 1 + b y 1 = a y 2 + b x 2 − ⌊ a b ⌋ × b y 2 = a y 2 + b ( x 2 − ⌊ a b ⌋ y 2 ) ax_1+by_1=ay_2+bx_2-\lfloor\frac{a}{b}\rfloor\times by_2=ay_2+b(x_2-\lfloor\frac{a}{b}\rfloor y_2) ax1+by1=ay2+bx2−⌊ba⌋×by2=ay2+b(x2−⌊ba⌋y2)
因为 a = a , b = b a=a,b=b a=a,b=b,所以 x 1 = y 2 , y 1 = x 2 − ⌊ a b ⌋ y 2 x_1=y_2,y_1=x_2-\lfloor\frac{a}{b}\rfloor y_2 x1=y2,y1=x2−⌊ba⌋y2
将 x 2 , y 2 x_2,y_2 x2,y2 不断代入递归求解直至 gcd \gcd gcd(最大公约数,下同)为0
递归x=1,y=0
回去求解。
// 求x, y,使得ax + by = gcd(a, b)
int extend_gcd(int a, int b, int &x, int &y){
if (!b){
x = 1; y = 0;
return a;
}
int d = extend_gcd(b, a % b, y, x);
y -= (a/b) * x;
return d;
}
裴蜀定理
是一个关于最大公约数的定理。
其内容是:
设 a , b a,b a,b 是不全为零的整数,则存在整数 x , y x,y x,y, 使得 a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b).
进一步结论
设自然数 a、b 和整数 n。a 与 b 互素。考察不定方程:
a x + b y = n ax+by=n ax+by=n
其中 x 和 y 为自然数。如果方程有解,称 n 可以被 a、b 表示。
记 C = a b − a − b C=ab-a-b C=ab−a−b。由 a 与 b 互素,C 必然为奇数。则有结论:
对任意的整数 n,n 与 C − n C-n C−n 中有且仅有一个可以被表示。
即:可表示的数与不可表示的数在区间 [ 0 , C ] [0,C] [0,C] 对称(关于 C 的一半对称)。0 可被表示,C 不可被表示;负数不可被表示,大于 C 的数可被表示。
几何意义
重新观察方程 a x + b y = n ax+by=n ax+by=n,将它看成一条直线。直线与两坐标轴在第一象限围成三角形。
当 n < a b n<ab n<ab 的时候,这个直线在第一象限,至多只能通过一个整点。
根据上述讨论:当 n 可以被表示的时候,直线恰好经过一个整点;当 n 不可以被表示的时候,直线不经过整点(在第一象限)。
这结论也可以理解为:作三角形(0,0)(b,0)(0,a)。随着 n 从 0 不断增加,直线向右上方平移,整点会一个一个地通过直线,直到最后才撞上两个整点。
因此,小于等于 n 的能被表示的非负整数的数量,恰好就是直线 a x + b y = n ax+by=n ax+by=n(含)与两坐标轴(含)在第一象限围成三角形覆盖的整点个数。
另一种解释
考虑模 b 意义下每个剩余系中最小能被表示的值是多少——大于他们的可以通过增加若干个 b 得到。
观察原方程,a 的若干倍数 0 , a , ⋅ ⋅ ⋅ , ( b − 1 ) a 0, a,···, (b−1)a 0,a,⋅⋅⋅,(b−1)a 在 ( m o d b ) \pmod b (modb) 意义下互不相同。这些数恰好是这些最小值。那么当 n < a b n<ab n<ab 时,小于等于 n 的能被表示的非负整数的数量是:
∑ i = 0 [ n a ] [ n − i a b ] \sum\limits_{i=0}^{\left[\frac{n}{a}\right]}\left[\frac{n − ia}{b}\right] i=0∑[an][bn−ia]
这是一个非常经典的直线下整点问题,恰好是这条直线:
y = − a b x + n b y=-\frac{a}{b}x+\frac{n}{b} y=−bax+bn
即 a x + b y = n ax+by=n ax+by=n。
使用类欧几里得算法可以在 O ( log max ( a , b ) ) O(\log \max(a,b)) O(logmax(a,b)) 的时间内求解。因此我们得到了计算小于等于 n 的能被表示的非负整数的数量的工具。
n个整数间的裴蜀定理
设
a
1
,
a
2
,
a
3
⋯
a
n
a1,a2,a3\cdots an
a1,a2,a3⋯an为
n
n
n个整数,d是它们的最大公约数,那么存在整数
x
1
⋯
x
n
x1\cdots xn
x1⋯xn使得
x
1
∗
a
1
+
x
2
∗
a
2
+
⋯
x
n
∗
a
n
=
d
x1*a1+x2*a2+\cdots xn*an=d
x1∗a1+x2∗a2+⋯xn∗an=d。
特别来说,如果
a
1...
a
n
a1...an
a1...an存在任意两个数是互质的(不必满足两两互质),那么存在整数
x
1
⋯
x
n
x1\cdots xn
x1⋯xn使得
x
1
∗
a
1
+
x
2
∗
a
2
+
⋯
x
n
∗
a
n
=
1
x1*a1+x2*a2+\cdots xn*an=1
x1∗a1+x2∗a2+⋯xn∗an=1。证法类似两个数的情况。