跳转至

最大公约数

基本概念

  • GCD (Greatest Common Divisor): 最大公约数。
    • 含义:两个数 $a$ 和 $b$,求出能同时被 $a$ 和 $b$ 整除的最大数字
  • LCM (Least Common Multiple): 最小公倍数
    • 含义:两个数 $a$ 和 $b$,求出同时是 $a$ 和 $b$ 的最小倍数。

规定:$\gcd(a, 0) = \gcd(a, a) = a$


更相减损术

基本原理:

\[ \gcd(a, b) = \gcd(a, b - a) \quad (a \leq b) \]

证明思路

  • 设 $\gcd(a, b) = d$,则 $a = m\cdot d$, $b = n\cdot d$,其中 $\gcd(m, n) = 1$

则:

\[ \gcd(a, b - a) = \gcd(m\cdot d, n\cdot d - m\cdot d) = \gcd(m, n - m) \times d \]
  • 反证 $\gcd(m, n - m) = 1$:
    • 假设 $\gcd(m, n - m) = p > 1$
    • 则 $m = k_1\cdot p$,$n - m = k_2\cdot p$,$n = (k_1 + k_2)\cdot p$
    • 则 $\gcd(m, n) \geq p$,与 $\gcd(m, n) = 1$ 矛盾

适用于多个数字:

\[ \gcd(a, b, c, d, \dots) = \gcd(a, b-a, c-b, d-c, \dots) \]

辗转相除法(欧几里得算法)

\[ \gcd(a, b) = \gcd(b, a \bmod b) \]

理解

更相减损术是一次减去 $b$,而 $a \bmod b$ 是相当于多次减 $b$ 直到余数。

代码实现

int gcd(int a, int b) 
{
    if (b == 0) return a;
    return gcd(b, a % b);
}
  • 时间复杂度: $O(\log \max(a,b))$
    • 可以证明 $a\bmod b\leq \lfloor\frac{a}{2}\rfloor$ 当且仅当 $b\leq a$。
  • C++ 自带函数: __gcd(a, b)

最小公倍数 LCM

利用 GCD 进行计算:

\[ lcm(a, b) = \frac{a \times b}{\gcd(a, b)} \]
int lcm(int a, int b) 
{
    return a / gcd(a, b) * b;
}

多个数字的 GCD 和 LCM

GCD

int d = 0;
for (int i = 1; i <= n; i++) d = gcd(d, a[i]);

LCM

int m = 1;
for (int i = 1; i <= n; i++) m = lcm(m, a[i]);
  • 初始化值

  • GCD 为 $0$,因为 $\gcd(a, 0) = a$

  • LCM 为 $1$,因为 $\text{LCM}(1, a) = a$

应用

  • 给定一个序列 $a_1, a_2, \dots, a_n$,多组询问求 $\gcd(a_1+x,a_2+x,\ldots,a_n+x)$。

利用更相减损术可得:

\[\begin{aligned} &\gcd(a_1+x,a_2+x,\ldots,a_n+x)\\ =& \gcd(a_1+x,a_2-a_1,a_3-a_2,\ldots,a_n-a_{n-1}) \end{aligned}\]

由于 $\gcd$ 具有结合律,因此可以预处理 $d=\gcd(a_2-a_1,a_3-a_2,\ldots,a_n-a_{n-1})$。

这样每次询问就直接计算 $\gcd(a_1+x,d)$ 即可。