当前位置: 首页 > news >正文

C++ 数学-数论:算数基本定理及其经典 OJ 题流食般投喂

1. 引言:为什么需要算数基本定理?

在算法竞赛和编程面试中,数论问题常常是区分选手水平的关键。而算数基本定理(Fundamental Theorem of Arithmetic),作为数论的基石之一,为我们理解和解决一大类整数分解、约数、最大公约数、最小公倍数等问题提供了强大的理论武器。掌握它,就如同掌握了打开数论问题宝库的钥匙。

本文将用“流食般投喂”的方式,从零开始,带你彻底吃透算数基本定理,并辅以多道经典 OJ(Online Judge)题目进行实战演练,确保你不仅能理解理论,更能将其转化为解决实际问题的代码能力。

2. 算数基本定理:定义与理解

定理内容:任何一个大于 1 的自然数 N,都可以唯一地分解成有限个质数的乘积。

用数学公式表示为:

N = p₁^a₁ * p₂^a₂ * ... * pₖ^aₖ

其中,p₁, p₂, ..., pₖ是质数(p₁ < p₂ < ... < pₖ),a₁, a₂, ..., aₖ是正整数。

“唯一”的含义:如果不考虑质因数的排列顺序,这种分解方式是唯一的。例如,12 = 2² * 3,而不能是 2 * 2 * 3 以外的其他质数组合。

3. 核心推论与应用方向

从算数基本定理可以直接推导出许多重要结论,这些结论是解题的关键:

  • 正约数个数:N = p₁^a₁ * p₂^a₂ * ... * pₖ^aₖ,则 N 的正约数个数为d(N) = (a₁ + 1) * (a₂ + 1) * ... * (aₖ + 1)
  • 正约数之和:N 的所有正约数之和为σ(N) = (1 + p₁ + p₁² + ... + p₁^a₁) * ... * (1 + pₖ + pₖ² + ... + pₖ^aₖ)
  • 最大公约数 (GCD) 与最小公倍数 (LCM):将两数分别质因数分解后,GCD 取各质因数指数的最小值,LCM 取各质因数指数的最大值。
  • 判断整除关系:若 A 能整除 B,则 A 的质因数分解是 B 的质因数分解的子集(即 A 的每个质因数的指数都不大于 B 中对应质因数的指数)。

4. C++ 实现:质因数分解

算法的核心是试除法。我们从最小的质数 2 开始,逐个尝试去除 N。

#include <iostream> #include <vector> #include <map> using namespace std; // 返回一个映射,键为质因数,值为对应的指数 map<int, int> primeFactorization(int n) { map<int, int> factors; // 处理因子 2 while (n % 2 == 0) { factors[2]++; n /= 2; } // 处理奇数因子 for (int i = 3; i * i <= n; i += 2) { while (n % i == 0) { factors[i]++; n /= i; } } // 如果最后剩下的 n 是大于 2 的质数 if (n > 1) { factors[n]++; } return factors; } int main() { int num = 360; // 360 = 2^3 * 3^2 * 5 map<int, int> factors = primeFactorization(num); cout << num << " = "; bool first = true; for (auto &[prime, exp] : factors) { if (!first) cout << " * "; cout << prime << "^" << exp; first = false; } cout << endl; return 0; }

复杂度分析:最坏情况 O(√N),但当 N 是质数时需要遍历到 √N。可以使用更高效的 Pollard-Rho 算法处理大整数,但试除法在 OJ 中对于N ≤ 10^12通常是够用的。

5. 经典 OJ 题实战“投喂”

5.1 题目一:求正约数个数 (Luogu P1403)

问题描述:定义 f(n) 为 n 的正约数个数。给定 n,求∑_{i=1}^{n} f(i)

解题思路:直接对每个 i 分解求约数个数会超时。利用算数基本定理的推论,我们可以在筛法的过程中递推求出每个数的约数个数。

#include <iostream> #include <vector> using namespace std; int main() { int n; cin >> n; long long ans = 0; // 对于每个数 i,在 1~n 范围内,有 n/i 个数包含 i 这个约数 for (int i = 1; i <= n; ++i) { ans += n / i; } cout << ans << endl; return 0; }

5.2 题目二:最大公约数之和 (Luogu P1390)

问题描述:给定 n,求∑_{i=1}^{n} ∑_{j=i+1}^{n} gcd(i, j)

解题思路:利用欧拉函数 φ 的性质进行转化。设d = gcd(i, j),则满足gcd(i, j) = d的 (i, j) 对数为2 * ∑_{k=2}^{n/d} φ(k) - 1(当 i < j)。预处理欧拉函数后求和。

#include <iostream> #include <vector> using namespace std; vector<int> eulerSieve(int n) { vector<int> phi(n + 1); vector<int> primes; vector<bool> isPrime(n + 1, true); phi[1] = 1; for (int i = 2; i <= n; ++i) { if (isPrime[i]) { primes.push_back(i); phi[i] = i - 1; } for (int p : primes) { if (i * p > n) break; isPrime[i * p] = false; if (i % p == 0) { phi[i * p] = phi[i] * p; break; } else { phi[i * p] = phi[i] * (p - 1); } } } return phi; } int main() { int n; cin >> n; vector<int> phi = eulerSieve(n); long long ans = 0; for (int d = 1; d <= n; ++d) { long long cnt = 0; for (int k = 2; k <= n / d; ++k) { cnt += phi[k]; } cnt = cnt * 2 + 1; // 加上 (d, d) 这一对 ans += cnt * d; } // 减去所有 (i, i) 的情况,因为题目要求 i < j for (int i = 1; i <= n; ++i) { ans -= i; } cout << ans / 2 << endl; // 因为我们计算了 (i, j) 和 (j, i),需要除以2 return 0; }

5.3 题目三:质因数分解(NOIP 2012 普及组)

问题描述:给定正整数 n,将其质因数分解,按格式输出。

解题思路:直接使用第 4 节的质因数分解算法即可,注意输出格式。

6. 总结与进阶

算数基本定理是数论大厦的基石。通过本文的“流食般投喂”,你应该已经掌握了:

  1. 定理本身及其唯一分解的含义。
  2. 由定理推导出的核心公式(约数个数、约数和)。
  3. C++ 实现质因数分解的试除法。
  4. 如何运用定理解决三类经典 OJ 问题。

进阶学习方向:

  • 更高效的分解算法:学习 Pollard-Rho 算法应对更大的整数。
  • 线性筛法:用欧拉筛在线性时间内预处理出每个数的最小质因数,从而实现 O(log N) 的质因数分解。
  • 结合其他数论知识:将算数基本定理与欧拉定理、中国剩余定理、原根等知识结合,解决更复杂的组合数学与密码学问题。

理论是灰色的,实践之树常青。打开你的 IDE,把上面的代码敲一遍,再去 OJ 上提交验证,这才是“吃透”的唯一路径。

http://www.cnnetsun.cn/news/3313349.html

相关文章:

  • 中文新闻文本分类实战代码包:PyTorch版BERT/RNN/CNN四模型一键训练与推理
  • 闲鱼数据智能监控系统:从零构建自动化市场情报引擎
  • MATLAB LQR控制完整工程包:含建模、仿真、GUI界面与可运行模型
  • Windows热键冲突终极指南:如何用Hotkey Detective快速找出快捷键占用者
  • Bilibili-Old终极指南:5分钟免费恢复B站经典界面,找回你的专属观看体验
  • BurpSuite实战:挖掘文件上传功能中的XSS漏洞
  • Python实现合成控制法:从零构建可解释因果推断流程
  • AI绘画实战:Anima模型+ControlNet+LoRA技术整合完整指南
  • YOLOv8农业智能检测:大豆幼苗杂草识别完整项目实战
  • CentOS 7 devtoolset-11 升级:3步解决C++17编译,对比gcc 4.8.5性能提升实测
  • STC89C52单片机OLED数字频率计:1Hz–1MHz实时测量,含Keil工程与Proteus仿真
  • 如何在5分钟内彻底清理Zotero文献库重复条目:完整免费插件使用指南
  • 人形机器人工程攻坚期:关节模组、运动规划与场景泛化的技术深水区
  • 华为/思科 ACL 配置实战:3类ACL(2000/3000/4000)应用场景与5步部署流程
  • 基于TPD2017FN与STM32的工业负载控制方案设计
  • 如何在3分钟内完成iOS 14-16.6.1设备的终极安装指南
  • 3分钟解锁QQ音乐加密文件:免费开源qmc-decoder完整使用指南
  • 如何在Word中快速添加APA第7版参考文献格式:完整跨平台指南
  • 遗传算法进阶:从能跑通到可交付的可控演化实践
  • 百考通降AIGC服务,助您顺利通过学术检测,全面覆盖研究要素
  • Android Studio中文语言包:告别英文界面困扰,提升开发效率的完整指南
  • 锂离子电池组电压平衡与保护系统设计
  • 端到端自动驾驶博士培养:跨栈整合与系统可信能力重构
  • 立创EDA + AI 生成 STM32 原理图教程5
  • Unity集成思必驰SDK实现Android离线语音唤醒与指令识别全流程指南
  • Firewalld 日志配置 3 步实战:从默认关闭到独立日志文件(附 rsyslog 规则)
  • 5分钟掌握AI换脸神器:roop-unleashed零门槛深度伪造指南
  • 如何用多层架构设计打造稳定的自定义固件系统?
  • 2026年爆火的AI智能体工程师岗位解析|零基础小白程序员转型攻略
  • 终极解决方案:5步快速清理Zotero文献重复难题,让学术管理效率翻倍!