数学基础
1. 倍数筛法
vector<int> p[N]; // 约数
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j += i)
p[j].push_back(i);
- 在 \(\mathcal O(n\log n)\) 时间内生成每个数的约数表
- 说明了 \(n\) 以内每个数倍数的总个数、每个数约数的总个数都是 \(\mathcal O(n\log n)\) 的
2. 唯一分解定理
正整数 \(n\) 和末尾非零的指数序列一一对应
\(n=p_1^{\alpha_1}\cdot p_2^{\alpha_2}\cdot\cdot\!\cdot\!\cdot\cdot p_k^{\alpha_k}\)(非零映射形式)
\(k\) 次约数函数:\(\displaystyle \sigma_k(n)=\sum_{d|n}d^k\)
- \(\sigma_0(n)=(\alpha_1+1)\cdot(\alpha_2+1)\cdot\cdot\!\cdot\!\cdot\cdot(\alpha_k+1)\)(约数个数和)
- \(\sigma_1(n)=\left(1+p_1+\cdots+p_1^{\alpha_1}\right)\cdot \left(1+p_2+\cdots+p_2^{\alpha_2}\right)\cdot\cdot\!\cdot\!\cdot\cdot\left(1+p_k+\cdots+p_k^{\alpha_k}\right)=\prod_{i\in[1..k]}\left(\sum_{j\in[0..\alpha_i]}p_i^j\right)\)(约数和)
质因数分解 \(n!(n\le10^6)\):
一个质因数 \(p\) 在 \(n!\) 中的出现次数 \(=\left\lfloor\dfrac np\right\rfloor+\left\lfloor\dfrac n{p^2}\right\rfloor+\left\lfloor\dfrac n{p^3}\right\rfloor+\cdots\)
算这个复杂度 \(\mathcal O(\log n)\).
3. 埃氏筛法
int vis[N]; // 不是质数
vector<int> p[N]; // 质因数
for (int i = 2; i <= n; i++)
if (!vis[i]) { // i 是质数
p[i].push_back(i); // 标记 i 是 i 的质因数
for (int j = i + i; j <= n; j += i) {
vis[j] = 1; // 标记 j 不是质数
p[j].push_back(i); // 标记 i 是 j 的质因数
}
}
筛质数、找每个数的质因数
欧拉函数 \(\varphi(n)\) 表示 \([1..n]\) 中与 \(n\) 互质的数的个数
设 \(n=p_1^{\alpha_1}\cdot p_2^{\alpha_2}\cdot\cdot\!\cdot\!\cdot\cdot p_k^{\alpha_k}\)(非零映射形式)
则 \(\varphi(n)=n\left(1-\dfrac1{p_1}\right)\left(1-\dfrac1{p_2}\right)\cdots\left(1-\dfrac1{p_k}\right)\)
单个求解:\(\mathcal O(\sqrt n)\) 找到 \(n\) 的所有质因数,然后公式求解
前 \(n\) 个一起算:\(\mathcal O(n\log\log n)\) 找完每个数的所有质因数种类,每多找到一个质因数就多算一次
4. 欧氏筛法(线性筛)
设 \(\text P(x)\) 为 \(x\) 最小质因子,\(x\) 可以唯一表示成 \(x=\text P(x)\times i\) 的形式
对于每个合数 \(x\),若只被 \(x=\text P(x)\times i\) 形式不重不漏地枚举,就能保证复杂度为 \(\mathcal O(n)\)
循环外层是 \(i\),内层 \(p_j=\text P(x)\),为了保证 \(p_j\) 是 \(x=i\cdot p_j\) 最小的质因数,须有 \(p_j\le \text P(i)\)
vector<int> p; // 质数
int mnp[N]; // 最小质因子
for (int i = 1; i <= n; i++) {
if (!mnp[i]) p.push_back(i); // 添加 p[0]=1
for (int j = 0; p[j] <= mnp[i] && i * p[j] <= n; j++)
mnp[i * p[j]] = p[j];
}
另一个板子
vector<int> p; // 质数
int vis[N]; // 不是质数
for (int i = 2; i <= n; i++) {
if (!vis[i]) p.push_back(i);
for (int v : p) {
if (i * v > n) break;
vis[i * v] = 1;
if (!(i % v)) break; // 相当于 v = P(i),因为它是第一个整除 i 的质数
}
}
线性筛 \(\text{DP}\) 化问题
\(n\) 由 \(\dfrac n{\text P(n)}\) 递推而来
设 \(l(n)\) 是 \(n\) 的质因数列表,\(l(n)=l\left(\dfrac n{\text P(n)}\right)+\big(\text P(n)\big)\)
设 \(s(n)\) 是 \(n\) 的所有质因数的和(重复算多次),\(s(n)=s\left(\dfrac n{\text P(n)}\right)+\text P(n)\)
\(\varphi(n)=\begin{cases}\varphi\left(\dfrac n{\text P(n)}\right)\cdot(\text P(n)-1)\ \ \ \ \ &(n\text{ 为合数}\land \text P(n)\nmid\dfrac n{\text P(n)})\\\varphi\left(\dfrac n{\text P(n)}\right)\cdot\text P(n)&(n\text{ 为合数}\land\text P(n)\mid\dfrac n{\text P(n)})\\n-1&(n\text{ 为质数})\\1&(n=1)\end{cases}\)
5. 几个复杂度、结论和证明
整数 \(i\) 的质因数个数(可重复)\(\le\log_2i\in\mathcal O(\log i)\)
斯特林公式:\(n!\sim\sqrt{2\pi n}\left(\dfrac ne\right)^n\)
对数求和:\(\sum_{i=1}^n\ln i=\ln(n!)\sim\ln(\sqrt{2\pi n})+\ln n^n-\ln e^n\in\mathcal O(n\ln n)\)
调和数列求和:\(\sum_{i=1}^n\dfrac1i\sim\ln n+\gamma\in\mathcal O(\ln n)\)(\(\gamma\) 是欧拉函数,\(\gamma=0.5772\cdot\!\cdot\cdot\))
调和级数求和渐进界初等证明:
\(H_n=\dfrac11+\left(\dfrac12+\dfrac13\right)+\left(\dfrac14+\dfrac15+\dfrac16+\dfrac17\right)+\left(\dfrac18+\dfrac19+\cdots+\dfrac1{15}\right)+\cdots+\left(\cdots+\dfrac1n+0+0+\cdots\right)\)
取 \(2^m\le n<2^{m+1}\),其中 \(m\in\mathbb N\)
\(H_n\le\dfrac11+\left(\dfrac12+\dfrac12\right)+\left(\dfrac18+\cdots+\dfrac18\right)+\cdots+\dfrac1{2^{m+1}}\times2^{m+1}\le m+1\in\text O(\log n)\)
\(H_n\ge\dfrac12+\left(\dfrac14+\dfrac14\right)+\left(\dfrac18+\dfrac18+\dfrac18+\dfrac18\right)+\left(\dfrac1{16}+\cdots+\dfrac1{16}\right)+\cdots+\dfrac1{2^{m+1}}\times2^m+0\ge\dfrac m2\in\Omega(\log n)\)
质数定理:\(p=(2,3,5,7,11,\dots)\),\(p_n\sim n\ln n\);\(\pi(n)\) 表示 \(n\) 以内质数的个数,\(\pi(n)\sim\dfrac n{\ln n}\)
质数倒数和:\(\sum_{i=1}^{\pi(n)}\dfrac1{p_i}\sim\sum_{i=2}^{n/\ln n}\dfrac1{i\ln i}\in\mathcal O(\ln\ln n)\)
故埃氏筛法复杂度 \(\left\lfloor\dfrac n2\right\rfloor+\left\lfloor\dfrac n3\right\rfloor+\left\lfloor\dfrac n5\right\rfloor\cdots+\left\lfloor\dfrac n{p_{\pi(n)}}\right\rfloor\le\dfrac n2+\dfrac n3+\dfrac n5+\cdots+\dfrac n{p_{\pi(n)}}\in\mathcal O(n\ln\ln n)\)
- 在 \(\mathcal O(n\ln\ln n)\) 的时间内求出每个数的质因数种类、每个质数
- \(n\) 以内每个质数倍数的总个数、每个数的质因数种类数的总数都是 \(\mathcal O(n\ln\ln n)\) 的
感性理解 \(\varphi(n)=n\left(1-\dfrac1{p_1}\right)\left(1-\dfrac1{p_2}\right)\cdots\left(1-\dfrac1{p_k}\right)\):
\(n\) 每个质因数的倍数都不与 \(n\) 互质,而一个质因数 \(p_i\) 的倍数大概应该占其中的 \(\dfrac1{p_i}\),每次乘一遍筛掉这些倍数
严格证明(容斥):
设 \(n\) 有两个不同质因数 \(p,q\),我们需要筛掉 \(n\) 以内 \(p\) 和 \(q\) 的所有倍数,即 \(n-\dfrac np-\dfrac nq+\dfrac n{pq}\),先筛 \(p\),再筛 \(q\),最后加上重复筛的 \(pq\)
发现是容斥,可以改写成 \(n\left(1-\dfrac1p\right)\left(1-\dfrac1q\right)\)
同理,若 \(n\) 有若干个质因子 \(p_1,p_2,\dots,p_k\),全部筛完后剩余的数即为与 \(n\) 互质的数,故 \(\varphi(n)=n\left(1-\dfrac1{p_1}\right)\left(1-\dfrac1{p_2}\right)\cdots\left(1-\dfrac1{p_k}\right)\).
欧拉函数的积性:若 \(\gcd(a,b)=1\),有 \(\varphi(ab)=\varphi(a)\varphi(b)\)
因为 \(\gcd(a,b)=1\),\(a\) 与 \(b\) 没有公共质因子,故用上面的算式可以证到
6. 小结
- 倍数筛法
- 筛掉每个数的所有倍数
- \(\mathcal O(n\ln n)\)
- \(n\) 以内每个数的所有倍数:\(\mathcal O(n\ln n)\)
- \(n\) 以内每个数的所有约数:\(\mathcal O(n\ln n)\)
- 埃氏筛法
- 筛掉每个质数的所有倍数
- \(\mathcal O(n\ln\ln n)\)
- \(n\) 以内每个质数的所有倍数:\(\mathcal O(n\ln\ln n)\)
- \(n\) 以内每个数的质因数种类数:\(\mathcal O(n\ln\ln n)\)
- 欧氏筛法
- 筛掉每个质数作为最小质因数时的所有倍数
- \(\mathcal O(n)\)
- \(n\) 以内每个数乘上不超过这个数的最小质因数的每个质数:\(\mathcal O(n)\)
- \(n\) 以内每个数的最小质因数:\(\mathcal O(n)\)
两个重要结论
- 质数定理:\(p_n\sim n\ln n\),\(\pi(n)\sim\dfrac n{\ln n}\)
- 斯特林公式:\(n!\sim\sqrt{2\pi n}\left(\dfrac ne\right)^n\)
三种数列求和的渐进表示
- \(\sum_{i=1}^n\dfrac1i\in\mathcal O(\ln n)\)
- \(\sum_{i=1}^{\pi(n)}\dfrac1{p_i}\sim\sum_{i=2}^{n/\ln n}\dfrac1{i\ln i}\in\mathcal O(\ln\ln n)\)
- \(\sum_{i=2}^n\log i\in\mathcal O(n\log n)\)
可用定积分证明两个渐进复杂度
1. 约数个数与根号
正整数 \(n\) 的所有约数按乘起来为 \(n\) 为原则,两两配对
设 \(pq=n\),且 \(0<p\le\sqrt n\),则有 \(q\ge\sqrt n\)
\(n\) 的约数个数不超过 \(2\sqrt n\in\mathcal O(\sqrt n)\)
2. 分解质因数与大质因数性质
若对 \(n\) 以内所有数质因数分解,筛法找到质因数种类后逐个除法,不超过 \(\mathcal O(n\log n)\)
单个数:暴力
for (int i = 2, q = n; q != 1; i++)
for (; q % i == 0; q /= i) fac[++cnt] = i;
优化 1:只枚举质数
性质:任何一个正整数 \(n\),大于 \(\sqrt n\) 的质因数最多 \(1\) 个
证明:若有 \(2\) 个,显然不行
优化 2:若 \(i>\sqrt q\),则 \(q\) 是唯一最大的质因数,可停止分解
例题:给出 \(l,r(1\le l\le r\le10^{14})\),问有多少 \(x\) 满足 \(x\mid r\) 且 \(l\mid x\).
首先判断 \(l\mid r\),然后质因数分解 \(\frac rl\),再算出它有多少个约数.
例题:给出 \(n(n\le 10^{12})\),求 \(\displaystyle\sum_{i=1}^n\left\lfloor\dfrac ni\right\rfloor\)
利用 \(\sqrt n\) 进行分类讨论:
-
\(i\le\sqrt n\):直接算
-
\(i>\sqrt n\):则所有可能的 \(\left\lfloor\dfrac ni\right\rfloor\) 一共 \(\sqrt n\) 种
故枚举 \(x=\left\lfloor\dfrac ni\right\rfloor\),它对应的 \(i\) 的范围:\(\left[\left\lfloor\dfrac n{x+1}\right\rfloor+1,\left\lfloor\dfrac nx\right\rfloor\right]\),每次 \(\mathcal O(1)\) 乘起来即可
3. 约数个数更严格的界
结论:\(n\) 的约数个数 \(d(n)\le n^{\frac c{\ln\ln n}}\)
其中 \(c=1.066\),为 \(n=6983776800=2^5\times3^3\times5^2\times7\times11\times13\times17\times19\) 时取等
分析复杂度时使用,需要记忆形式和常数 \(c\)
\(\mathcal O(\sqrt n)\) 的复杂度仍然有意义:例如某算法复杂度为 \(\mathcal O(d(n)^3)\),则先花 \(\mathcal O(\sqrt n)\) 的时间找所有约数也是值得的
4. 单个 \(n\) 的质因数种数
结论:用 \(\omega(n)\) 表示 \(n\) 质因数的种数,有 \(\omega(n)\in\mathcal O\left(\frac{\ln n}{\ln\ln n}\right)\)
证明:设 \(k=\omega(n)\) 构造最坏情况
两边取对数
故令 \(k\sim\dfrac{\ln n}{\ln\ln n}\),则有
5. 小结
各种上界
- 质因数种数 \(\omega\)
- 单个正整数 \(n\):\(\mathcal O\left(\dfrac{\ln n}{\ln\ln n}\right)\)
- \(n\) 以内所有正整数:\(\mathcal O(n\ln\ln n)\)
- 质因数个数
- 单个正整数 \(n\):\(\mathcal O(\ln n)\)
- \(n\) 以内所有正整数:\(\mathcal O(n\ln n)\)
- 约数个数 \(d\)
- 单个正整数 \(n\):\(\le2\sqrt n\) 或 \(\le n^{c/\ln\ln n}\)
- \(n\) 以内所有正整数:\(\mathcal O(n\ln n)\)