Project Euler 521
Project Euler 521
题目
Smallest prime factor
Let \(\text{smpf}(n)\) be the smallest prime factor of \(n\).
\(\text{smpf}(91)=7\) because \(91=7\times13\) and \(\text{smpf}(45)=3\) because \(45=3\times3\times5\).
Let \(S(n)\) be the sum of \(\text{smpf(i)}\) for \(2 \le i \le n\).
E.g. \(S(100)=1257\).
Find \(S(10^{12}) \bmod 10^9\).
解决方案
对“没有小于 \(p\) 的质因子”的数,定义两类函数(都只统计 \([2,x]\),不含 \(1\)):
\[ C_p(x)=\#\{m\in\mathbb Z:2\le m\le x,\operatorname{smpf}(m)\ge p\}, A_p(x)=\sum_{\substack{2\le m\le x\\\operatorname{smpf}(m)\ge p}} m. \]
并令\(\Omega\)是质数集合。
接下来先对合数部分进行计数,对固定质数 \(p\),满足 \(\operatorname{smpf}(n)=p\) 且 \(n\) 为合数的数恰为 \(n=p\cdot m\),其中
- \(m\ge p\)(保证 \(n\ge p^2\) 合数),
- \(\operatorname{smpf}(m)\ge p\),
- \(m\le \lfloor N/p\rfloor\)。
因此这类 \(m\) 的个数为\(C_p\left(\left\lfloor\dfrac{N}{p}\right\rfloor\right)-C_p(p-1).\) 它们对 \(S(N)\) 的贡献为 \[ p\cdot \left(C_p\left(\left\lfloor\frac{N}{p}\right\rfloor\right)-C_p(p-1)\right). \]
当我们把允许的最小质因子阈值”从 \(p\) 推进到下一个质数 \(p^+\)(也就是把质数 \(p\) 也排除掉),需要从集合里删掉所有“最小质因子为 \(p\) 的合数:这些数在 \([2,x]\) 中恰是 \(p\cdot t\),其中 \(t\ge p\) 且 \(\operatorname{smpf}(t)\ge p\) 且 \(t\le \lfloor x/p\rfloor\)。因此:
\[ C_{p^+}(x)=C_p(x)-(C_p(\lfloor x/p\rfloor)-C_p(p-1)), A_{p^+}(x)=A_p(x)-p(A_p(\lfloor x/p\rfloor)-A_p(p-1)). \]
注意这里 刻意不删掉质数 \(p\) 本身:因为上式只删 \(p\cdot t\) 且 \(t\ge p\),不会涉及 \(p\cdot 1\)。最终剩下来的恰好就是所有质数(它们的最小质因子就是它们自己),可以作为质数部分直接加回去。
设 \(v=\lfloor\sqrt N\rfloor\)。我们对上述\(p\)的处理,不会超过\(v\),这是因为任意合数 \(n\le N\) 必有一个质因子 \(\le \sqrt n\le v\),因此当我们把所有质数 \(p\le v\) 的“最小质因子为 \(p\) 的合数贡献”都加完后,剩下没覆盖的数只能是质数(以及 \(1\),但我们从不统计 \(1\))。
换言之:
- 合数部分只需枚举 \(p\le v\);
- 最终剩下的 \(A_{v+1}(N)\) 就是 \(\displaystyle{\sum_{p\le N,p\in\Omega}p}\)(所有质数和)。
所以答案是 \[ S(N)= \left(\sum_{\substack{p\le v,p\in \Omega}}p\cdot \left(C_p(\lfloor N/p\rfloor)-C_p(p-1)\right)\right)+A_{v+1}(N). \]
在递推里会出现很多形如 \(\lfloor x/p\rfloor\) 的值。因此,对固定 \(N\),所有可能出现的自变量只需要两类:
- 小值:\(x\le v\)(直接数组下标存)。
- 大值:\(x=\left\lfloor\dfrac{N}{i}\right\rfloor\),其中 \(1\le i\le v\)(这类也只有 \(v\) 个)。
因此我们维护两套表:
s_cnt[x], s_sum[x]表示当前阈值下的 \(C(x),A(x)\),其中 \(x\in[0,v]\);l_cnt[i], l_sum[i]表示当前阈值下的 \(C(\lfloor N/i\rfloor),A(\lfloor N/i\rfloor)\),其中 \(i\in[1,v]\)。
初始化对应阈值 \(p=2\)(尚未筛掉任何质数):\(\displaystyle{C_2(x)=x-1, A_2(x)=\sum_{k=2}^{x}k=\frac{x(x+1)}{2}-1.}\)
之后对每个质数 \(p\le v\) 用上一节的递推更新所有需要的 \(x\)。
代码
1 |
|