数论基础与进阶 (Number Theory)
本篇文档系统化构建了从基础整除、同余系,到莫比乌斯反演、二次剩余与高阶筛法的工业级数论知识体系。数论不仅是数学的桂冠,更是现代公钥密码学的逻辑基石。
1. 核心理论体系与严密证明
1.1 算术基本定理 (Fundamental Theorem of Arithmetic, FTA)
定理表述:任何大于 1 的整数 都可以唯一地表示为一系列素数的乘积: ,其中 为素数,。
系统化推导过程:
1. 存在性证明 (Existence)
我们使用强数学归纳法证明:
- 基础步: 是素数,结论成立。
- 归纳步:假设对于所有 结论均成立。
- 若 为素数,则 已经是素因子分解。
- 若 为合数,则存在 使得 。由归纳假设, 和 都可以分解为素数乘积。将两者的分解合并,即可得到 的素因子分解。
2. 关键引理:欧几里得引理 (Euclid's Lemma)
若素数 满足 ,则 或 。 证明:若 ,则 。根据裴蜀定理,存在整数 使得 。 等式两边同乘 :。 因为 且 (由已知 ),故 整除它们的和,即 。
3. 唯一性证明 (Uniqueness)
假设 有两种不同的素因子分解:
- 由 知 。根据欧几里得引理, 必然整除某个 。
- 由于 也是素数,故 。
- 将 和 从等式两边消去,得到 。
- 重复此过程,最终所有的因子都会一一对应相等,且 。
1.2 同余类与剩余系 (Congruence & Residue Systems)
代数结构定义:
- 模 剩余类环 :由 构成的加法交换群与乘法半群。
- 乘法群 :由与 互质的剩余类构成的阿贝尔群,其阶数为 。
1.3 欧拉定理与费马小定理
欧拉定理:若 ,则 。
证明 (群论视角): 由于 ,则 。根据拉格朗日定理,群中任何元素的阶必然整除群的阶。故 。
费马小定理:若 为素数且 ,则 。
1.4 原根 (Primitive Roots)
定义:若 模 的阶 ,则称 为模 的一个原根。 存在性定理:模 有原根当且仅当 ,其中 为奇素数。
判定法则: 对于 ,其原根 满足:对于 的所有质因子 ,均有 。
1.5 二次剩余 (Quadratic Residues)
对于 ,若有解则 是模 的二次剩余。 勒让德符号 (Legendre Symbol):
欧拉准则 (Euler's Criterion):。
二次互反律 (Law of Quadratic Reciprocity): 对于不同奇素数 :
1.6 素数分布理论 (Theory of Prime Distribution)
定理 1:素数无限性 (Euclid's Theorem) 假设素数有限,设为 。构造 。 则 必有质因子 。若 ,则 ,矛盾。故存在无穷多个素数。
定理 2:切比雪夫定理 (Chebyshev's Theorem) 令 为不超过 的素数个数,则存在正数 使得: 这证明了素数分布的密度大致为 。
定理 3:素数定理 (Prime Number Theorem) 黎曼 Zeta 函数关联:。素数定理的深层证明依赖于 在 线上无零点。
1.7 同余方程收敛与 Hensel 引理
线性同余方程组 (CRT): 有解的充要条件是 。若 两两互质,则在 下有唯一解。
Hensel 引理 (收敛提升): 若 是整系数多项式,且 ,若 ,则存在唯一的 使得 。 证明:泰勒展开 。 要使 ,只需 。 由于 ,其逆元存在,故 唯一确定。这展现了同余解从低幂向高幂收敛的过程。
1.8 素性检验与大数分解 (Miller-Rabin & Pollard's Rho)
Miller-Rabin 算法:收敛性与错误界分析 对于大奇数 ,设 ( 为奇数)。Miller-Rabin 基于费马小定理的逆命题及二次探测定理: 若 ,则 。
- 随机选择基 。
- 计算 。若 或 ,则 通过测试。
- 否则,重复计算 共 次。若某次出现 ,则通过。
- 错误率界限:对于合数 ,单次测试通过(即误判为素数)的概率不超过 。若进行 轮测试,误报率为 。对于 ,选取特定基 即可实现确定性判定。
Pollard's Rho 算法:生日悖论启发式收敛 利用 构造伪随机序列。 核心逻辑:若 ,则 是 的一个非平凡因子。 收敛分析:根据生日悖论,期望在 步内找到环。配合 Brent 优化(倍增检查)可显著提升效率。
Check Solution (Miller-Rabin + Pollard's Rho C++)
#include <iostream>
#include <algorithm>
#include <random>
typedef __int128_t int128;
typedef long long ll;
ll qpow(ll a, ll b, ll m) {
ll res = 1;
a %= m;
while (b) {
if (b & 1) res = (int128)res * a % m;
a = (int128)a * a % m;
b >>= 1;
}
return res;
}
bool miller_rabin(ll n, ll a) {
if (qpow(a, n - 1, n) != 1) return false;
ll d = n - 1;
while (!(d & 1)) {
d >>= 1;
ll x = qpow(a, d, n);
if (x == n - 1) return true;
if (x != 1) return false;
}
return true;
}
bool is_prime(ll n) {
if (n < 2) return false;
static ll bases[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
for (ll a : bases) {
if (n == a) return true;
if (!miller_rabin(n, a)) return false;
}
return true;
}
ll pollard_rho(ll n) {
if (n == 4) return 2;
if (is_prime(n)) return n;
std::mt19937_64 rng(std::random_device{}());
while (true) {
ll c = rng() % (n - 1) + 1;
auto f = [&](ll x) { return ((int128)x * x + c) % n; };
ll x = rng() % n, y = f(x);
while (x != y) {
ll d = std::gcd(std::abs(x - y), n);
if (d > 1) return d;
x = f(x), y = f(f(y));
}
}
}
2. 积性函数与 Dirichlet 卷积
2.1 莫比乌斯函数
定义:
性质证明:。 利用二项式展开:。
2.2 Dirichlet 卷积
。
- 恒等元:。
- 逆元:若 ,则 存在 Dirichlet 逆元 。
- 重要关系:。
3. 高阶技术:杜教筛与反演进阶
3.1 杜教筛 (Du's Sieve)
求解 ,利用卷积 : 复杂度通过预处理前 项可优化至 。
3.2 莫比乌斯反演 (Mobius Inversion)
- 约数形式:。
- 倍数形式:。
4. 综合练习与 C++ 解答
练习 1:[P3306] 随机数生成器 (BSGS 应用)
求 首次达到 的最小 。
Check Solution (思路)
- 当 :只需判断 。
- 当 :,线性同余方程。
- 当 :利用等比数列求和 。
- 整理得 。
- 使用 BSGS (Baby-step Giant-step) 求解离散对数。
Check Solution (C++)
#include <iostream>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
ll qpow(ll a, ll b, ll p) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
ll bsgs(ll a, ll b, ll p) {
if (1 % p == b % p) return 0;
map<ll, ll> hash;
ll m = ceil(sqrt(p));
ll t = b % p;
for (int j = 0; j < m; j++) {
hash[t] = j;
t = t * a % p;
}
a = qpow(a, m, p);
t = 1;
for (int i = 1; i <= m; i++) {
t = t * a % p;
if (hash.count(t)) return i * m - hash[t];
}
return -1;
}
void solve() {
ll p, a, b, x, t;
cin >> p >> a >> b >> x >> t;
if (x == t) { cout << 1 << endl; return; }
if (a == 0) {
if (b == t) cout << 2 << endl;
else cout << -1 << endl;
return;
}
if (a == 1) {
if (!b) cout << -1 << endl;
else {
ll val = (t - x % p + p) % p;
ll inv = qpow(b, p - 2, p);
cout << val * inv % p + 1 << endl;
}
return;
}
ll inv_a1 = qpow(a - 1, p - 2, p);
ll constant = b * inv_a1 % p;
ll target = (t + constant) % p;
ll start = (x + constant) % p;
if (!start) {
if (!target) cout << 1 << endl;
else cout << -1 << endl;
return;
}
ll res = bsgs(a, target * qpow(start, p - 2, p) % p, p);
if (res == -1) cout << -1 << endl;
else cout << res + 1 << endl;
}
练习 2:[P4549] 裴蜀定理 (Bezout's Identity)
求 的最小正整数 。 定理:。
练习 3:[P3846] BSGS 模板
求解 ,其中 为质数。
练习 4:[P5491] 二次剩余 (Cipolla 算法)
求 的所有解。
Check Solution (C++)
// Cipolla 算法核心实现
struct Complex { ll r, i; };
ll W;
Complex mul(Complex a, Complex b, ll p) {
return { (a.r * b.r % p + a.i * b.i % p * W % p) % p, (a.r * b.i % p + a.i * b.r % p) % p };
}
ll cipolla(ll n, ll p) {
n %= p;
if (qpow(n, (p - 1) / 2, p) == p - 1) return -1; // 无解
ll a;
while (true) {
a = rand() % p;
W = (a * a % p - n + p) % p;
if (qpow(W, (p - 1) / 2, p) == p - 1) break;
}
Complex res = { 1, 0 }, base = { a, 1 };
ll b = (p + 1) / 2;
while (b) {
if (b & 1) res = mul(res, base, p);
base = mul(base, base, p);
b >>= 1;
}
return res.r;
}
练习 5:[P4777] 扩展中国剩余定理 (EXCRT)
求解方程组 ,其中 不一定两两互质。
Check Solution (思路)
- 采用合并方程思想。设有方程 和 。
- 转化为 ,即 。
- 利用 EXGCD 求解 ,若无解则原方程组无解。
- 合并后的新模数为 ,新余数为 。
Check Solution (C++)
#include <iostream>
using namespace std;
typedef __int128_t int128; // 使用 int128 防止溢出
long long exgcd(long long a, long long b, long long &x, long long &y) {
if (!b) { x = 1, y = 0; return a; }
long long d = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return d;
}
void solve() {
int n; cin >> n;
long long m1, r1, m2, r2;
cin >> m1 >> r1;
for (int i = 1; i < n; i++) {
cin >> m2 >> r2;
long long k1, k2;
long long d = exgcd(m1, m2, k1, k2);
long long target = (r2 - r1 % m2 + m2) % m2;
k1 = (int128)k1 * (target / d) % (m2 / d);
r1 += k1 * m1;
m1 = m1 / d * m2;
r1 = (r1 % m1 + m1) % m1;
}
cout << (long long)r1 << endl;
}
练习 6:[P3807] 卢卡斯定理 (Lucas Theorem)
对于质数 ,计算 。
Check Solution (思路)
- 定理:。
- 递归求解 ,基本情况为 时返回 1。
- 预处理阶乘及其逆元以加速 的计算。
Check Solution (C++)
#include <iostream>
using namespace std;
typedef long long ll;
ll qpow(ll a, ll b, ll p) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
ll C(ll n, ll m, ll p) {
if (m > n) return 0;
if (m > n / 2) m = n - m;
ll a = 1, b = 1;
for (int i = 0; i < m; i++) {
a = a * (n - i) % p;
b = b * (i + 1) % p;
}
return a * qpow(b, p - 2, p) % p;
}
ll lucas(ll n, ll m, ll p) {
if (!m) return 1;
return lucas(n / p, m / p, p) * C(n % p, m % p, p) % p;
}
void solve() {
ll n, m, p; cin >> n >> m >> p;
cout << lucas(n + m, n, p) << endl;
}
大师寄语:数论不仅仅是处理数字,更是处理结构。当你能通过 Dirichlet 卷积看穿函数的相互作用时,你便掌握了调和级数背后的规律。