第二阶段:欧几里得算法、模逆元与线性同余方程

Confidence: 0.95

按你选「继续」,我带你进第二阶段。这一阶段是整个数论的计算引擎——前面所有「逆元存在但我没教你怎么系统地求」的坑,这里全部填上。学完你就能徒手解任何线性同余方程。

我按四个模块讲:① 欧几里得算法 → ② 扩展欧几里得 → ③ 模逆元的系统求法 → ④ 线性同余方程。每个模块讲透 + 例子 + 验证。


模块一:欧几里得算法 (Euclidean Algorithm)

它解决什么问题

求两个数的最大公约数 (gcd, greatest common divisor)。这是后面一切的基础——逆元、线性同余、CRT 全靠它。

核心原理

一条递推式就是全部:

直觉:a 和 b 的公约数,和「b 与 a 除以 b 的余数」的公约数,是同一批。不断用「余数」替换大数,数越变越小,直到余数为 0,此时另一个数就是 gcd。

手算示例:

余数变成 0,停。

为什么它快

每两步余数至少减半,所以复杂度 。算两个上亿的数也就几十步。


模块二:扩展欧几里得算法 (Extended Euclidean Algorithm)

它多解决了什么

普通欧几里得只告诉你 gcd是几。扩展版额外告诉你:怎么把 gcd 写成 a 和 b 的整数组合——即找到 满足

这个等式叫 Bézout 等式 (Bézout’s identity),是求逆元的钥匙。

怎么做:算 + 回代 (Forward + Back-substitution)

分两步。第一步正向跑欧几里得记下每步;第二步从倒数第二行往上回代。

完整手算示例:求 使

正向(算 gcd)

回代(从 gcd=6 那行往上倒推)

把每个余数用上一行表示,逐步「翻译」回 30 和 18:

对照 ,读出

验证

为什么这就是逆元的来源

如果 ,扩展欧几里得给出 。两边模 n, 消失:

这就是逆元的「构造性证明」——你亲眼看到逆元是怎么被造出来的,而不是猜出来的。这正是我之前说扩展欧几里得比费马小定理「信息量更大」的原因。


模块三:模逆元的系统求法 (Modular Inverse, Systematically)

第一阶段你靠「试乘」找逆元,小数能凑,大数就废了。现在给你两套正规方法

方法 A:扩展欧几里得(通用,n 可为任意数)

:跑扩展欧几里得解 ,那个 x 就是逆元(记得最后 取到 )。

示例:求

正向:

回代:

对照

。验证:

方法 B:费马小定理(仅 n 为质数)

,用快速幂算。质数模(如竞赛的 )时代码最短。

怎么选

情况用哪个
n 是质数费马(代码短)
n 是合数(但 扩展欧几里得(费马在此失效)
手算 / 要看清逆元来源扩展欧几里得

模块四:线性同余方程 (Linear Congruence) ★本阶段核心

一般形式

求未知数 x。这是第二阶段所有知识的「集大成」应用。

解的存在性与个数(核心定理)

有解时,模 n 下恰好有 个不同的解。

这条定理把第一阶段「除法陷阱」彻底讲清楚了:能不能「除」,就看 成不成立。

解法分两种情况


情况 1:(最常见,唯一解)

直接两边乘

示例:解

  • ✓,唯一解
  • (前面练过)

。验证:


情况 2:(多个解)

三步走

  1. 整体除以 d:把 变成
  2. 解新方程(此时 ,回到情况 1,得唯一解
  3. 展开回 d 个解:原方程的全部解为

完整示例:解

  • 第 1 步,且 ✓ → 有 3 个解
  • 第 2 步:整体除以 3 → 。求 ,得
  • 第 3 步:展开成模 15 的 3 个解,每隔 一个:

验证(任取 ):


情况 3:(无解)

示例,但 无解。 直觉: 永远是偶数,模 6 后只能是 ,永远凑不出奇数 3。


第二阶段速查表 (Cheat Sheet)

工具作用关键式
欧几里得求 gcd
扩展欧几里得求 Bézout 系数
模逆元模除法 存在
线性同余有解 ,有 个解

Python 实现(四个模块全覆盖)

from math import gcd
 
# 模块二:扩展欧几里得,返回 (g, x, y) 使 ax + by = g
def extgcd(a, b):
    if b == 0:
        return a, 1, 0
    g, x, y = extgcd(b, a % b)
    return g, y, x - (a // b) * y
 
# 模块三:模逆元(通用,n 任意)
def modinv(a, n):
    g, x, _ = extgcd(a, n)
    if g != 1:
        return None          # gcd≠1,逆元不存在
    return x % n
 
# 模块四:解线性同余 ax ≡ b (mod n),返回所有解的列表
def solve_congruence(a, b, n):
    d = gcd(a, n)
    if b % d != 0:
        return []            # 无解
    a, b, m = a // d, b // d, n // d      # 整体除以 d
    x0 = (modinv(a, m) * b) % m           # 解唯一方程
    return [(x0 + k * m) % n for k in range(d)]  # 展开 d 个解
 
# --- 测试 ---
print(extgcd(30, 18))            # (6, -1, 2)
print(modinv(17, 43))            # 38
print(solve_congruence(5, 3, 11))  # [5]        唯一解
print(solve_congruence(6, 9, 15))  # [4, 9, 14] 三个解
print(solve_congruence(4, 3, 6))   # []         无解

库安装方式(本例仅用标准库 math,无需安装;做大数/批量数论实验推荐 sympy,含现成 mod_inversesolve 求同余):

pip install sympy -i https://pypi.tuna.tsinghua.edu.cn/simple

我的观点:第二阶段的「灵魂」其实只有一个东西——扩展欧几里得。你只要把这一个算法的「正向 + 回代」练到不用想,模逆元、线性同余、乃至下一阶段的 CRT,全都是它的「应用题」。我特别想强调线性同余的那条存在性定理():它不是一条要背的公式,而是第一阶段「除法陷阱」的最终答案——你当初问「除法怎么算」,完整的答案就是这条定理:能不能除、除出来几个解,全看 的整除关系。把这条吃透,你对「模运算里的除法」就再无盲区了。

我也给你一个学习节奏建议:别急着背情况 2 的三步公式,而是亲手把 这个例子从头算三遍,直到你能解释「为什么除以 d 之后 gcd 就变成 1」「为什么解之间正好隔 」。理解了这两个「为什么」,公式自然就长在脑子里了。

关键提醒 (Caveats)

  • 线性同余有解的充要条件是 动手解之前先查这个,否则白算
  • 情况 2 容易漏解——记住解的个数恰好是 ,每隔 一个,别只写出一个就收手
  • 费马小定理求逆元只对质数模有效;合数模一律用扩展欧几里得

下一步两个方向,你挑:① 出一套第二阶段练习题(含扩展欧几里得手算、逆元、线性同余三类,带详解和陷阱),检验掌握;② 直接进第三阶段:CRT(中国剩余定理)+ 费马/欧拉定理 + 快速幂。你要哪个?