数论(一)

整除

对任意 定义 ,它由 的所有倍数构成。对于 ,如果 则称 整除 记为 ,否则记为 。当 时,我们称 为 的因数或因子。

最小公倍数、最大公因数、互素

以下选定 ,并考虑一族整数 。

  • 记这族整数的最小公倍数least common multiple为

  • 记这族整数的最大公因数greatest common divisor为

  • 若 ,则称 互素,这也相当于说 没有 以外的公因子。

整数的带余除法

对于任意整数 ,若 ,则存在唯一的 使得 而 。

证明 不妨假定 。考虑集合

这是 的非空子集,故有极小元,记为 ;相应地 。必然有 ,否则 将给出 使得 ,与 的极小性质矛盾。这就说明 的存在性。

至于唯一性,设 ,其中 而 。因为 既被 整除,又有 ,易证唯一的可能是 ,从而由 推得 。

根据上述命题中的唯一性,带余除法中的余数 当且仅当 。

设 为 的非空子集,满足以下性质

此时存在唯一的 使得 。

上述两个性质是说 中任意两整数相加仍然在 中, 中任意整数的倍数仍然在 中。

证明 先讨论 的存在性。不妨设 ,否则唯一的取法是 。注意到 。取 为 中的最小正整数。包含关系 自明。至于 ,设 ,用带余除法表为 ,其中 。不难验证 属于 ,于是 必为 ,否则将给出 中比 更小的正整数,矛盾。

至于 的唯一性,若正整数 满足 ,则它们相互整除,故唯一的可能是 。

对给定的 ,定义 的子集

按照惯例,极端情形 (即“空和”)按 来解释。

Bézout's identity(裴蜀恒等式 )

设 为整数,则

作为推论, 互素的充要条件是存在 使得 。

证明 不妨设 不全为 ,否则等式两边按定义同等于 。据上述引理取 ,使得 。不难验证对于任意正整数 ,我们有

这就足以表明 。

基于上述结果, 蕴含 可以表为 的形式;反之,若存在 使得 ,则 当然互素。

欧几里得引理

若 使得 且 ,则 。

证明 由于 ,裴蜀定理蕴含存在 使得 。于是 ,而 ,所以有 。

计算 gcd(a, b)

求正整数 的最大公因数。

不妨设 。设 用带余除法表作 ,其中 。若 是 的公因数,则 整除 ;反之,若 是 的公因数则 整除 。即 和 有同一群公因数,自然有

这引出如下递归算法:

若继续作带余除法若

一言以蔽之,从 开始反复作带余除法,直到余数为零。

此算法称为辗转相除法,也称欧几里得算法Euclid's algorithm。

例子:计算

用辗转相除法计算 的过程可以用如下序列表示

从第三项开始,每一项都是前两项相除的余数;这样反复做带余除法,直到余数为 。

前一次的除数是下一次的被除数,而余数(可视为被除数的“残留”)是一下次的除数;被除数与除数前后角色翻转,此即“辗转”之义。

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

gcd(a, b) 的返回值可能是负数,例如 gcd(-2, 0) 返回 。

一般的,gcd(a, b) 的返回值是 。

若要保证 gcd(a, b) 返回值非负,可改为

int gcd(int a, int b) {
    return b == 0 ? abs(a) : gcd(b, a % b);
}

辗转相除法的时间复杂度

设 。辗转相除计算 最多可能做多少次除法?

用辗转相除法计算 的最大公因数,假设一共做了 次除法运算,那么我们得到两个序列

  • 余数序列:。
  • 商序列:。

对每个 ,有

设 是正整数,, 是 除以 的余数。那么 。

证明 若 ,那么根据余数的定义有 。若 ,那么 。

设 是整数,。用辗转相除法计算 ,做除法的次数不超过 。

证明:假设一共做了 次除法,写出余数序列

我们有

根据上一页的命题,我们有

分别看 和 ,有

若 是奇数,我们有

也就是有 ,所以

若 为偶数,此时 ,有 且 ,所以 ,我们有

也就是有 ,所以

计算 lcm(a, b)

求正整数 的最小公倍数。

对任意正整数 有 。

证明 设 ,则根据最大公因数的定义,存在整数 使得 , 且 。

令 ,代入 得 。于是有 ,可见 是 的公倍数。

设 是 和 的任意一个公倍数,即 且 。以 代入 得 ,所以存在整数 使得 。以 和 代入 ,得 。两边约去 ,得 。由于 ,根据欧几里得引理,必有 。所以存在整数 ,使 ,代入 ,得 。因为 是整数,所以 。

因为 的任意公倍数都能被 整除,且 是 的公倍数,所以 就是 最小公倍数。

丢番图方程

设 是整数,求方程 的整数解。

根据 Bézout's identity,,所以方程有解当且仅当 。

设 是整数, 不都是 。设整数 满足 ,那么方程 的全部整数解为

其中 是任意整数。

证明:先证充分性。
令 。将 和 代入 ,得

所以 是方程的解。

再证必要性。
设 是方程的任意一组整数解,即 ,同时我们有 ,两式相减,得 ,即

设 ,,此时必然有 ,代入上式并除以 ,得

于是可见 整除 。由于 ,根据欧几里得引理,我们有

也就是说,存在整数 使得 ,即 。

若 ,即 ,此时必有 ,则 的值唯一,是 ,而 可取任一整数。此时 ,而 确实可以取到每个整数。

若 ,将 代入 ,得 ,除以 ,得 ,即 。

丢番图方程

设 是整数,求方程 的整数解。

扩展 gcd 算法

我们用辗转相除法计算 ,除了可以得到 ,还能得到两个整数 使得 。这就是所谓扩展 gcd 算法。

具体的计算方法有两种:一是正推,一是倒推。

正推的扩展 gcd 算法

用辗转相除法计算 ,写出余数序列

我们可以按 的顺序,把每个 写成

的形式,其中 是整数。

最后 就使得 .

我们取 和 。

从 和 推

将 和 代入

得

改写成

我们可以取

我们以计算 为例,演示正推的扩展 gcd 算法。

pair<int,int> extgcd(int a, int b) {
    int u = 1, v = 0;
    while (b != 0) {
        int q = a / b;
        a -= q * b;
        u -= q * v;
        swap(a, b);
        swap(u, v);
    }
    return {a, u};
}

extgcd(a, b) 返回的两个整数 ,。

  • 使得存在整数 满足 。
    或者说 使得 整除 。

倒推的扩展 gcd 算法

用辗转相除法计算 ,写出余数序列

我们可以按 的顺序,把 写成

的形式,其中 是整数。

最后, 就使得 。

就是 ,我们取 ,。

从 推

将 代入 ,得

改写成

将此式与 对比,可见我们可以取

我们以计算 为例,演示倒推的扩展 gcd 算法。

int extgcd(int a, int b, int& x, int& y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    int q = a / b;
    int g = extgcd(b, a - q * b, y, x);
    y -= x * q;
    return g;
}

正推

倒推

正推和倒推给出的 是一样的,这并非巧合。

C++ 里的 % 运算符和 / 运算符

设 是整数,。

  • 如果 整除 ,那么 。如果 不整除 ,此时必有 ,那么
    • ,
    • 的符号与 相同,
    • 。
  • a == (a / b) * b + (a % b) 总是成立。

扩展 gcd 算法给出的 x, y 的大小

设 是整数, 且 ,设 。那么 extgcd(a, b, x, y) 给出的 满足

证明:用归纳法。回忆到条件是 且 。
当 时,,extgcd(a, b, x, y) 给出 。此时 , 且 ,命题成立。

当 时,根据归纳假设,递归调用 extgcd(b, a % b, y, x) 给出的 满足 ,。设 a / b,根据 和 ,有

和

回忆到 与 符号相同,所以 。于是有

用同样的方法,我们还可以证明

设 是整数,, 且 ,设 。
那么 extgcd(a, b, x, y) 给出的 满足

解丢番图方程

此方程有解当且仅当 。

具体的,如果 ,也就是 ,那么当且仅当 时有解,此时任意整数 都是解。

如果 不全是 ,那么

  1. 用扩展 gcd 算法算出 和整数 使得 。
  2. 如果 ,那么 就是 的一个解,否则方程无解。

当 较大时,计算 或 可能溢出。

求丢番图方程 的一组解 使得 和 都不很大。

假设 且 。

void diophantine(long long a, long long b, long long c, long long& x, long long& y) {
    long long dx = c / a;
    c -= dx * a;
    long long dy = c / b;
    c -= dy * b;
    long long g = extgcd(a, b, x, y);
    x = dx + x * (c / g) % b;
    y = dy + y * (c / g) % a;
}

设 是整数,,, 且 。如果整数 使得 ,那么 x / b + y / a == 0。

注意:/ 是 C++ 的除法,向零取整。

证明:设 = x / b, = x % b, = y / a, = y % a。我们要证明 .
有 ,,,, 或与 同号, 或与 同号。

若 ,那么 。以下设 不全为 。首先证明 与 不同号。若它们同号,则 。因为 不全是 ,右边至少是 ,但 ,矛盾。所以 与 不同号。因此 与 也不可能同号,于是 。

由 得 。
同理,。所以 。
又 ,所以 。

另一方面,有 .
令 ,则 。若 ,则

这与 矛盾。

同余式

设 。称 是 mod 同余的,如果 ;此关系也写作

线性同余方程

设 是整数,。求方程 的整数解。

整数 使得 ,也就是说存在整数 使得 。于是可见同余方程 和丢番图方程 同解。我们立即得到

  • 存在整数 使得 当且仅当 。
  • 设整数 是方程 的一个解,那么此方程的全部整数解为 ,其中 是任意整数。也就是说 和 等价。

线性同余方程组

设 是整数,,。
求方程组 的整数解。

整数 满足 ,也就是说 使得

  • 存在整数 满足 且 。

所以这样的 和满足 的整数对 一一对应。可见 就是丢番图方程 的解 。设 是一个解,那么全部解为

其中 是任意整数。将上式代入 ,得

注意到 就是 。于是可见

  • 方程组 等价于 。

这样对齐会导致 \implies 左边的空格较小,不是正确的对齐方式。

首先我们写出 $$ \begin{align} \gcd(a, b) &= x_i r_i + y_i r_{i+1} \label{eq} \tag{1} \\ \gcd(a, b) &= x_{i-1} r_{i-1} + y_{i-1} r_i \label{eq2} \tag{2} \end{align} $$