Project Euler 646
Project Euler 646
题目
Bounded Divisors
Let \(n\) be a natural number and \(p_1^{\alpha_1}\cdot p_2^{\alpha_2}\dots p_k^{\alpha_k}\) its prime factorisation.
Define the Liouville function \(\lambda(n)\) as \(\lambda(n) = (-1)^{\sum\limits_{i=1}^{k}\alpha_i}\).
(i.e. \(-1\) if the sum of the exponents \(\alpha_i\) is odd and \(1\) if the sum of the exponents is even. )
Let \(S(n,L,H)\) be the sum \(\lambda(d) \cdot d\) over all divisors \(d\) of \(n\) for which \(L \leq d \leq H\).
You are given:
\(\bullet\, S(10! , 100, 1000) = 1457\)
\(\bullet\, S(15!, 10^3, 10^5) = -107974\)
\(\bullet\, S(30!,10^8, 10^{12}) = 9766732243224\).
Find \(S(70!,10^{20}, 10^{60})\) and give your answer modulo \(1\,000\,000\,007\).
解决方案
令\(N=70,L=10^{20},H=10^{60},M=1000000007\)。
定义\(\gamma(d)=\lambda(d)d.\)若\(d\)的质因子分解为 \(\displaystyle{d=\prod_{i=1}^{k} p_i^{e_i},}\)则\(\displaystyle{\gamma(d)=\left(\prod_{i=1}^{k}p_i^{e_i}\right)\left(\prod_{i=1}^{k}(-1)^{e_i}\right)=\prod_{i=1}^{k}\left((-1)^{e_i}p_i^{e_i}\right)=\prod_{i=1}^{k}(-p_i)^{e_i}.}\)因此 \(\gamma\) 是完全乘法性的(更准确:对互素的数乘法性足够):若 \(\gcd(a,b)=1\),则\(\gamma(ab)=\gamma(a)\gamma(b).\)
将区间求和写成前缀差:令\(\displaystyle{F(T)=\sum_{\substack{d\mid N!\\d\le T}}\gamma(d),}\)则\(S(N!,L,H)=F(H)-F(L-1).\) 在本题中端点 \(L,H\) 不是 \(N!\) 的因子时,\(F(L-1)=F(L)\),
于是可用\(S(N!,L,H)=F(H)-F(L).\)实际实现里直接用对数阈值 \(\log H\) 与 \(\log L\) 即可。
对每个素数 \(p\le N\),令 \(\beta_p=v_p(N!)\),由 Legendre 公式得 \(\displaystyle{\beta_p=\sum_{t\ge 1}\left\lfloor\frac{N}{p^t}\right\rfloor.}\)因此\(\displaystyle{N! = \prod_{p\le N} p^{\beta_p}.}\) 每个因子 \(d\mid N!\) 唯一对应一组指数选择 \(0\le e_p\le \beta_p\),并且\(\displaystyle{d=\prod_{p\le N} p^{e_p}, \gamma(d)=\prod_{p\le N}(-p)^{e_p}.}\)
接下来考虑 Meet-in-the-middle思想解决。选取一个划分,将素数集合拆成不交两部分 \(A,B\),定义\(\displaystyle{P=\prod_{p\in A}p^{\beta_p}, Q=\prod_{p\in B}p^{\beta_p},}\)则 \(N!=PQ\) 且 \(\gcd(P,Q)=1\)。
任意 \(d\mid N!\) 有唯一表示\(d=xy, x\mid P,y\mid Q,\)并且由乘法性\(\gamma(d)=\gamma(xy)=\gamma(x)\gamma(y).\)
于是前缀和\(F(T)\)可写为 \[ F(T)=\sum_{\substack{x\mid P}}\gamma(x)\sum_{\substack{y\mid Q\\xy\le T}}\gamma(y). \]
直接比较 \(xy\le T\) 会遇到 \(T\) 高达 \(H\) 的大整数。改用对数:\(xy\le T\Longleftrightarrow \log x+\log y\le \log T.\)
做法:
- 枚举所有 \(y\mid Q\),保存二元组 \((\log y ,\gamma(y))\)。
- 按 \(\log y\) 升序排序,做前缀和数组\(\displaystyle{Y_{s}[k]=\sum_{i=0}^k \gamma(y_i).}\)
- 对每个 \(x\mid P\),计算阈值\(\log y\le \log T-\log x,\)在排序后的 \(\log y\) 上二分出最大下标 \(k\),贡献为\(\gamma(x)\cdot Y_{s}[k].\)
当然,我们并不需要生成超过 \(T\) 的数:因为 \(x\ge 1,y\ge 1\),若 \(x>T\) 则任何组合都不可能满足 \(xy\le T\)。因此在生成每一侧因子时,可以用对数剪枝:当把已有项乘上一次 \(p\),对数增加 \(\log p\);若超过 \(\log T\) 就停止继续扩展该条链。此外,\(\gamma\) 的更新是把当前模值乘上 \((-p)\bmod M\)。
代码
1 | from math import log |