最大公约数#
GCD ,即 Greatest Common Divisor .
一组整数的最大公约数就是指这组整数的最大的公共约数 .
怎么全是废话
那么要如何求解一组整数的 gcd 捏?
我们先考虑两个数 a,b 的情况 .
令 a=bq+r(q,r∈N) ,则 amodb=r∈[0,b) ,假设 d=gcd(a,b) ,有 d∣a, d∣b ,因此 d∣r,于是我们发现 gcd(b,r)=d=gcd(a,b) .
综上,gcd(a,b)=gcd(b,amodb) ,于是我们可以利用这个性质不断递归求解直到 b=0 ,这时候的 a 就是 gcd 了.
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=p1ka1p2ka2⋯pnkan
b=p1kb1p2kb2⋯pnkbn
根据定义可知 ,
lcm(a,b)=p1min(ka1,kb1)p2min(ka2,kb2)⋯pnmin(kan,kbn)
gcd(a,b)=p1max(ka1,kb1)p2max(ka2,kb2)⋯pnmax(kan,kbn)
而 max(a,b)+min(a,b)=a+b ,因此 gcd(a,b)×lcm(a,b)=a×b .
所以 lcm(a,b)=gcd(a,b)a×b .
对于多于 2 的整数数目的情况,处理方法和 gcd 是一样的 .
扩展欧几里得算法#
扩展欧几里得算法(Extended Euclidean algorithm, EXGCD)常用来求解 ax+by=gcd(a,b) 的一组可行解的情况 .
我们设 ax1+by1=gcd(a,b) ,bx2+(amodb)y2=gcd(b,amodb) .
下面我们来看看 x1,y1 和 x2,y2 之间的关系 .
将 amodb=a−⌊ba⌋×b 和 gcd(a,b)=gcd(b,amodb) 带入第二个方程,得到
bx2+ay2−⌊ba⌋×b×y2=gcd(a,b)
整理得到
ay2+b(x2−⌊ba⌋y2)=gcd(a,b)
与第一个方程比对可以发现 x1=y2,y1=x2−⌊ba⌋y2 .
因此我们可以不断递归求解 gcd(a,b) 直到 b=0 ,显然此时的 xn=1 ,然后考虑 xn−1,yn−1 的情况,此时的 b=gcd(a,b) ,而 a=0 ,所以 xn−1=yn=0 ,综上,我们得到边界情况 xn=1,yn=0 同时求得了 gcd(a,b) .
最后我们在不断回溯时修改 x,y 的值即可得到 ax+by=gcd(a,b) 的一组可行解 .
int exgcd(int a, int b, int &x, int &y) {
int ret = exgcd(b, a % b, x, y);
x = y, y = tmp - a / b * y;