最大公约数
GCD ,即 Greatest Common Divisor .
一组整数的最大公约数就是指这组整数的最大的公共约数 .
怎么全是废话
那么要如何求解一组整数的 gcd 捏?
我们先考虑两个数 a , b a,b a , b 的情况 .
令 a = b q + r ( q , r ∈ N ) a=bq+r(q,r\in\mathbb{N}) a = b q + r ( q , r ∈ N ) ,则 a m o d b = r ∈ [ 0 , b ) a \bmod b=r\in[0,b) a m o d b = r ∈ [ 0 , b ) ,假设 d = gcd ( a , b ) d=\gcd(a,b) d = g cd( a , b ) ,有 d ∣ a , d ∣ b d\mid a,~d\mid b d ∣ a , d ∣ b ,因此 d ∣ r d\mid r d ∣ r ,于是我们发现 gcd ( b , r ) = d = gcd ( a , b ) \gcd(b,r)=d=\gcd(a,b) g cd( b , r ) = d = g cd( a , b ) .
综上,gcd ( a , b ) = gcd ( b , a m o d b ) \gcd (a,b)=\gcd(b,a\bmod b) g cd( a , b ) = g cd( b , a m o d b ) ,于是我们可以利用这个性质不断递归求解直到 b = 0 b=0 b = 0 ,这时候的 a 就是 gcd 了.
1 2 3 int gcd (int a, int b) { return b ? gcd (b, a % b) : a; }
当整数的数量大于 2 时,我们求解前两个数的 gcd 与后一个数的 gcd ,便得到前 3 个数的 gcd ,依次进行下去,最后得到的便是这 n 个数的 gcd .
对了,这个算法就是欧几里得算法 .
最小公倍数
LCM ,即 Least Common Multiple .
一组整数的公倍数,是指同时是这组数中每一个数的倍数的数 . 0 是任意一组整数的公倍数 .
一组整数的最小公倍数,是指所有正的公倍数里面,最小的一个数 .
语言贫瘠,直接蒯 oi-wiki 上的了
同样也是先考虑两个数 a , b a,b a , b 的情况 .
将 a , b a,b a , b 写成素数的乘积的形式 .
a = p 1 k a 1 p 2 k a 2 ⋯ p n k a n a=p_1^{k_{a_1}}p_2^{k_{a_2}}\cdots p_n^{k_{a_{n}}}
a = p 1 k a 1 p 2 k a 2 ⋯ p n k a n
b = p 1 k b 1 p 2 k b 2 ⋯ p n k b n b=p_1^{k_{b_1}}p_2^{k_{b_2}}\cdots p_n^{k_{b_{n}}}
b = p 1 k b 1 p 2 k b 2 ⋯ p n k b n
根据定义可知 ,
lcm ( a , b ) = p 1 min ( k a 1 , k b 1 ) p 2 min ( k a 2 , k b 2 ) ⋯ p n min ( k a n , k b n ) \operatorname{lcm}(a,b)=p_1^{\min(k_{a_1},k_{b_1})}p_2^{\min(k_{a_2},k_{b_2})}\cdots p_n^{\min(k_{a_n},k_{b_{n}})}
l c m ( a , b ) = p 1 m i n ( k a 1 , k b 1 ) p 2 m i n ( k a 2 , k b 2 ) ⋯ p n m i n ( k a n , k b n )
gcd ( a , b ) = p 1 max ( k a 1 , k b 1 ) p 2 max ( k a 2 , k b 2 ) ⋯ p n max ( k a n , k b n ) \gcd(a,b)=p_1^{\max(k_{a_1},k_{b_1})}p_2^{\max(k_{a_2},k_{b_2})}\cdots p_n^{\max(k_{a_n},k_{b_{n}})}
g cd( a , b ) = p 1 m a x ( k a 1 , k b 1 ) p 2 m a x ( k a 2 , k b 2 ) ⋯ p n m a x ( k a n , k b n )
而 max ( a , b ) + min ( a , b ) = a + b \max(a,b)+\min(a, b)=a+b max ( a , b ) + min ( a , b ) = a + b ,因此 gcd ( a , b ) × lcm ( a , b ) = a × b \gcd(a,b)\times\operatorname{lcm}(a,b)=a\times b g cd( a , b ) × l c m ( a , b ) = a × b .
所以 lcm ( a , b ) = a × b gcd ( a , b ) \operatorname{lcm}(a,b)=\dfrac{a\times b}{\gcd(a,b)} l c m ( a , b ) = g cd( a , b ) a × b .
对于多于 2 的整数数目的情况,处理方法和 gcd 是一样的 .
扩展欧几里得算法
扩展欧几里得算法(Extended Euclidean algorithm, EXGCD)常用来求解 a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) a x + b y = g cd( a , b ) 的一组可行解的情况 .
我们设 a x 1 + b y 1 = gcd ( a , b ) ax_1+by_1=\gcd(a,b) a x 1 + b y 1 = g cd( 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) b x 2 + ( a m o d b ) y 2 = g cd( b , a m o d b ) .
下面我们来看看 x 1 , y 1 x_1,y_1 x 1 , y 1 和 x 2 , y 2 x_2,y_2 x 2 , y 2 之间的关系 .
将 a m o d b = a − ⌊ a b ⌋ × b a\bmod b=a-\lfloor\frac{a}{b}\rfloor\times b a m o d b = a − ⌊ b a ⌋ × b 和 gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a\bmod b) g cd( a , b ) = g cd( b , a m o d b ) 带入第二个方程,得到
b x 2 + a y 2 − ⌊ a b ⌋ × b × y 2 = gcd ( a , b ) bx_2+ay_2-\lfloor\frac{a}{b}\rfloor\times b\times y_2=\gcd(a,b)
b x 2 + a y 2 − ⌊ b a ⌋ × b × y 2 = g cd( a , b )
整理得到
a y 2 + b ( x 2 − ⌊ a b ⌋ y 2 ) = gcd ( a , b ) ay_2+b(x_2-\lfloor\frac{a}{b}\rfloor y_2)=\gcd(a, b)
a y 2 + b ( x 2 − ⌊ b a ⌋ y 2 ) = g cd( a , 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 x 1 = y 2 , y 1 = x 2 − ⌊ b a ⌋ y 2 .
因此我们可以不断递归求解 gcd ( a , b ) \gcd(a,b) g cd( a , b ) 直到 b = 0 b=0 b = 0 ,显然此时的 x n = 1 x_n=1 x n = 1 ,然后考虑 x n − 1 , y n − 1 x_{n-1},y_{n-1} x n − 1 , y n − 1 的情况,此时的 b = gcd ( a , b ) b=\gcd(a,b) b = g cd( a , b ) ,而 a ≠ 0 a\not= 0 a = 0 ,所以 x n − 1 = y n = 0 x_{n-1}=y_n=0 x n − 1 = y n = 0 ,综上,我们得到边界情况 x n = 1 , y n = 0 x_n=1,y_n=0 x n = 1 , y n = 0 同时求得了 gcd ( a , b ) \gcd(a,b) g cd( a , b ) .
最后我们在不断回溯时修改 x , y x,y x , y 的值即可得到 a x + b y = gcd ( a , b ) ax+by=\gcd(a, b) a x + b y = g cd( a , b ) 的一组可行解 .
1 2 3 4 5 6 7 8 9 10 int exgcd (int a, int b, int &x, int &y) { if (!b) { x = 1 , y = 0 ; return a; } int ret = exgcd (b, a % b, x, y); int tmp = x; x = y, y = tmp - a / b * y; return ret; }
Comments