C++数论

一、数论核心概念与算法

1. 整除与素数

整除:整数 \(a\) 整除 \(b\)(记作 \(a|b\))当且仅当 \(b = ka\)\(k \in \mathbb{Z}\))。
素数:只能被 1 和自身整除的大于 1 的自然数。
素数判定

  • 朴素法:检查 \(2 \sim \sqrt{n}\) 是否有因数。
  • 优化:只需检查 \(2 \sim \sqrt{n}\) 内的素数是否为因数(结合素数筛法)。
    代码示例(C++)
// 判断素数(优化版)
bool isPrime(int n) {
    if (n <= 1) return false;
    for (int i = 2; i * i <= n; ++i) {
        if (n % i == 0) return false;
    }
    return true;
}

2. 最大公约数(GCD)与最小公倍数(LCM)

  • GCD 算法:欧几里得算法(递归实现)
  • LCM 公式\(LCM(a, b) = \frac{|a \cdot b|}{GCD(a, b)}\)
  • 代码示例

3. 扩展欧几里得算法

用于求解线性同余方程 \(ax + by = \gcd(a, b)\) 的整数解 \((x, y)\)
代码示例(C++)

void extendedGCD(int a, int b, int& x, int& y) {
    if (b == 0) {
        x = 1; y = 0;
        return;
    }
    int x1, y1;
    extendedGCD(b, a % b, x1, y1);
    x = y1;
    y = x1 - (a / b) * y1;
}

4. 中国剩余定理(CRT)

解决形如 \(x \equiv a_i \pmod {m_i}\) 的同余方程组。
核心思想:通过构造乘积和逆元逐步合并解。
应用场景:时间同步、模块化计算等。

5. 费马小定理与快速幂

  • 费马小定理:若 \(p\) 为素数且 \(a\) 不整除 \(p\),则 \(a^{p-1} \equiv 1 \pmod p\)
  • 快速幂算法:高效计算 \(a^b \bmod m\),时间复杂度 \(O(\log b)\)
    代码示例(C++)
int fastPower(int a, int b, int mod) {
    int res = 1;
    while (b > 0) {
        if (b & 1) res = (res * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res;
}

二、排列组合与概率

1. 排列与组合

  • 排列(有序选择):\(P(n, m) = \frac{n!}{(n-m)!}\)
  • 组合(无序选择):\(C(n, m) = \frac{n!}{m!(n-m)!}\)
  • 代码示例(C++)

2. 容斥原理

用于计算满足多个条件的集合元素个数。
公式\(|A_1 \cup A_2 \cup \cdots \cup A_n| = \sum |A_i| - \sum |A_i \cap A_j| + \sum |A_i \cap A_j \cap A_k| - \cdots\)
应用场景:统计问题、集合计数。

3. 鸽巢原理(抽屉原理)

\(n\) 个物品放入 \(m\) 个抽屉(\(n > m\)),则至少有一个抽屉包含超过 1 个物品。
扩展应用:证明存在性问题,如哈希冲突、生日悖论等。

三、数论算法实战应用

1. 组合生成与排列生成

  • 递归回溯法生成所有组合/排列。
  • 优化:迭代生成(如字典序排列)。
    示例:生成 \(n\) 个元素中 \(m\) 个元素的组合。

2. 质因数分解

  • 试除法分解质因数。
  • Pollard-Rho 算法(分解大数)。
    代码示例(C++)
// 试除法分解质因数
map<int, int> factorize(int n) {
    map<int, int> factors;
    for (int i = 2; i * i <= n; ++i) {
        while (n % i == 0) {
            factors[i]++;
            n /= i;
        }
    }
    if (n > 1) factors[n]++;
    return factors;
}

3. 密码学应用:RSA 算法

  • 密钥生成:选择大素数 \(p, q\),计算 \(n = pq\)\(e\)\(\phi(n) = (p-1)(q-1)\) 互素,求 \(d\) 使 \(ed \equiv 1 \pmod {\phi(n)}\)
  • 加密:\(c = m^e \bmod n\);解密:\(m = c^d \bmod n\)

4. 模线性方程求解

  • 求解 \(ax \equiv b \pmod m\):使用扩展欧几里得算法。
  • 模逆元:求 \(a^{-1} \bmod m\)(当 \(a\)\(m\) 互素时存在)。

四、高级技巧与优化

1. 素数筛法

  • 埃拉托斯特尼筛法\(O(n \log \log n)\)\(n\) 内素数。
  • 线性筛法(欧拉筛)\(O(n)\) 高效筛法,避免重复标记。
    代码示例(C++)
// 欧拉筛法
vector<bool> isPrime(n + 1, true);
vector<int> primes;
for (int i = 2; i <= n; ++i) {
    if (isPrime[i]) primes.push_back(i);
    for (int j = 0; j < primes.size() && i * primes[j] <= n; ++j) {
        isPrime[i * primes[j]] = false;
        if (i % primes[j] == 0) break; // 关键优化
    }
}

2. 数论函数

  • 欧拉函数 \(\phi(n)\):小于 \(n\) 且与 \(n\) 互素的数的个数。
  • 莫比乌斯函数 \(\mu(n)\):用于数论求和的变换。
  • 积性函数:研究函数性质与乘积的关系。

3. 高精度计算

  • 使用 __int128 或自定义大数类处理超大数运算。(参考我的文章《C++高精模版》)
  • 优化技巧:Karatsuba 算法(快速乘法)、Montgomery 算法(模乘加速)。

五、实战案例

1. 求解线性同余方程组

// 中国剩余定理(CRT)求解
vector<pair<int, int>> equations; // {(a1, m1), (a2, m2),...}
int M = accumulate(equations.begin(), equations.end(), 1, [](int x, auto p) { return x * p.second; });
int ans = 0;
for (auto [a, m] : equations) {
    int Mi = M / m;
    int inv = extendedGCD(Mi, m, x, y);
    ans = (ans + a * Mi * inv) % M;
}
cout << ans << endl;

2. 组合数学问题

  • 例题:从 \(n\) 个不同元素中选 \(m\) 个的组合数,模 \(10^9+7\)
  • 解法:预处理阶乘及逆元,使用组合公式计算。

六、总结

数论是编程中不可或缺的工具,从基础算法到高级应用,它为密码学、组合优化、高效计算等领域提供了核心支撑。C++ 的高效特性使其成为实现数论算法的理想选择。掌握这些知识,可以解决从简单数学问题到复杂工程场景中的挑战。

参考资料

posted @ 2025-07-25 11:48  nebula_walk  阅读(39)  评论(0)    收藏  举报