欧几里得算法
最大公因数 #
$a$ 和 $b$ 的最大公因数记作 $gcd(a,b)$,简记为 $(a,b)$.
若 $a,b$ 有公因数 $d$,则 $a \bmod b = a - b \cdot\left\lfloor\frac{a}{b}\right\rfloor$ 也有因数 $d$. 也就是说,$a$ 和 $b$ 的所有公因数,同时也是 $b$ 和 $a \bmod b$ 的公因数,因此它们的最大公因数也相等.
$$gcd(a,b)=gcd(b,a \bmod b)$$
递归到 $b=0$ 时,$a$ 即为 $gcd(a,b)$.
时间复杂度为 $O(log{(a+b)})$.
int gcd(int a, int b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
最小公倍数 #
$a$ 和 $b$ 的最小公倍数记作 $lcm(a,b)$,简记为 $[a,b]$.
设 $gcd(a,b)=d$,则 $a=k_1d,b=k_2d$,所以:
$$lcm(a,b)=k_1k_2d=\frac{k_1d\cdot k_2d}{d}=\frac{ab}{gcd(a,b)}$$
时间复杂度为 $O(log{(a+b)})$.
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
扩展欧几里得算法 #
扩展欧几里得算法用于求方程 $ax+by=gcd(a,b)$ 关于 $x,y$ 的解,其中 $a,b$ 是常数.
设 $ax_1+by_1=gcd(a,b)$,
设 $bx_2+(a \bmod b)y_2=gcd(b,a \bmod b)$,
由 $gcd(a,b)=gcd(b,a \bmod b)$ 可知:
$$\begin{aligned} ax_1+by_1&=bx_2+(a \bmod b) y_2\\ &=bx_2+(a-\left\lfloor\frac{a}{b}\right\rfloor\cdot b) y_2\\ &=bx_2+ay_2-\left\lfloor\frac{a}{b}\right\rfloor\cdot by_2\\ &=ay_2+b(x_2-\left\lfloor\frac{a}{b}\right\rfloor\cdot y_2) \end{aligned}$$
$$∴\left\{\begin{aligned}x_1&=y_2\\y_1&=x_2-\left\lfloor\frac{a}{b}\right\rfloor\cdot y_2\end{aligned}\right.$$
因此,考虑先递归求解 $bx+(a \bmod b)\ y=gcd(a,b)$,再由其解推出 $ax+by=gcd(b,a \bmod b)$ 的解.
边界条件:当递归到 $b=0$ 时,一定有一组解 $\left\{\begin{aligned}x&=1\\y&=0\end{aligned}\right.$.
struct Set {
int x, y;
Set(int x, int y) : x(x), y(y) {}
};
Set exGcd(int a, int b) { // 求解 ax + by = gcd(a, b)
if (b == 0)
return Set(1, 0);
Set ans = exGcd(b, a % b); // 先递归求解 bx + (a % b)y = gcd(b, a % b)
return Set(ans.y, ans.x - (a / b) * ans.y);
}