min_25 筛与洲阁筛

1. \(F_k\) 函数

现在假设要求积性函数 \(f(x)\) 的前缀和,我们设 \(minp(x)\) 函数代表 \(x\) 的最小质因子是第几个质数,设 \(F_k(x)\) 函数表示在 \([2,x]\)\(minp(i)\geq k\)\(f(i)\) 的和。

这样,我们需要求的前缀和即为 \(F_1(n)+1\) 。考虑递归求解 \(F_k(x)\) 函数。

对于 \(F_k(x)\) ,只考虑 \(F_k(x)\) 所求的范围中的数。将最小因子 \(p_i\) 的影响全部去掉,枚举 \(p_i\) 对应的次数 \(c\) ,则 \([1,x]\) 当中所有 \(minp(x)=p^i\) 且唯一分解中 \(p_k\) 的次数恰好等于 \(c\) 的数的贡献都可以分离出一个 \(f(p_k^c)\) 。对于还有因数的数,接着递归求解。则有

\[F_k(x)=\sum_{i\geq k}\sum_{c\geq 1}[p_i^c\leq x]f(p_i^c)(1+F_{i+1}(x/p_i^c)) \]

这样复杂度比 \(O(n)\) 还要差。发现当 \(p_i^c\leq x<p_i^{c+1}\) 的时候,考虑贡献的数中不存在仍含有比 \(p_i\) 大的因数,不递归。

\[\begin{aligned} F_k(x)&=\sum_{i\geq k}\begin{pmatrix}f(p_i)+\sum_{c\geq 1}[p_i^{c+1}\leq x]f(p_i^c)F_{i+1}(x/p_i^c)+f(p_i^{c+1})\end{pmatrix}\\ &=\sum_{i=k}^{p_i\leq x}f(p_i)+\sum_{i\geq k}\sum_{c\geq 1}[p_i^{c+1}\leq x]f(p_i^c)F_{i+1}(x/p_i^c)+f(p_i^{c+1})\\ &=F_p(x)-F_p(p_{k-1})+\sum_{i\geq k}\sum_{c\geq 1}[p_i^{c+1}\leq x]f(p_i^c)F_{i+1}(x/p_i^c)+f(p_i^{c+1})\\ \end{aligned}\]

里面 \(F_p(x)\) 就是 \([1,x]\) 中质数的函数值的和。

然后你直接递归去做这个做法,它就和杜教筛类似,只在 \(x\) 为整除分块点的时候才会被遍历,看起来就很快了。

但这个做法有十分精密的复杂度证明:我们发现真的递归去求函数,每次 \(f(p_i^c)\) 事实上是求一个最大质因子是 \(p_i^c\) 的数的答案,这部分仍然是一个一个求的。所以这个做法事实上优化掉的是被质数前缀和 \(F_p(x)=F_p(p_{k-1})\) 求出的答案,也就是那些最大质因子是 \(p_i\) 仅有一次的数。

仔细思考,由于我们排除掉了 \(p_i^2>x\) 以至于不需要递归的 \(i\) 的枚举,事实上复杂度瓶颈就是求 \(f(p_i^c)\),也就是说复杂度是“最大质因数不是二次的数的个数”。

经过估算,这个复杂度在 \(O(\frac{n^\frac{3}{4}}{\log n})\),实际应用和杜教筛差不多快,\(10^{12}\) 可以跑。

不过需要预处理一个 \(F_p(x)\)

2.\(F_p\) 函数

这个时候 \(f(p)\) 通常形式简单,如 \(\varphi(p)=p-1\),我们不妨设 \(f'(x)=x-1\),并求 \(f'(x)\) 在所有质数点值的和。

于是设 \(F_p(x)\) 表示 \(\sum_{i=1}^{p_i\leq x} f'(p_i)\),仍然按埃氏筛的想法考虑。

\(G_k(x)=\sum_{i=1}^x f'(i) [i\in P||minp(i)>p_k]\) ,即为埃氏筛进行到 \(p_k\) 之后剩下的数,包括最大质因数大于 \(p_k\) 的数以及质数。则 \(F_p(x)=G_{|P|}(x)\) ,其中 \(P\) 为筛到 \(\sqrt n\) 的素数,因为埃氏筛只筛到 \(\sqrt n\) 即可。这样 \(G_0(x)=\sum_{i=1}^n f'(i)\) 是易于用求和公式计算的。

每次筛相当于把所有以 \(p_k\) 为最小质因数的数删掉,由于 \(f'(x)\) 也是积性函数,所以 \(-f'(p_k)G_{k-1}(n/p_k)\) ,因为 \(G_{k-1}\) 里最小值因数一定大于等于 \(p_k\),但是别忘了 \(G_{k-1}\) 里面还有小质数,于是再 \(+p_k^tG_{k-1}(p_{k-1})\) 把这些去掉。得到递推式

\[G_k(x)=G_{k-1}(x)+[p_k^2\leq x]p_k^t(G_{k-1}(p_{k-1})-G_{k-1}(n/p_k)) \]

3.代码实现

具体实现的时候做 \(F_k(x)\) 函数不需要所有的 \(F_p(x)\) 。分别考虑递归式里的两种情况。

首先是递推公式里用到的 \(F_p(p_{k-1})\)\(G_{k-1}(p_{k-1})\) 这些特殊点值,因为埃氏筛过程肯定不会用到 \(\sqrt n\) 以上的质数,所以这些点值就是 \(\sqrt n\) 以下的质数点值的前缀和。这个可以线性筛预处理。

然后 \(F_p(x)\) 会访问的点一定是 \(n\) 的整除分块点,更进一步,我们只算这些的话 \(G_k(x)\) 也只需要这些点。所以我们可以用一个数组把 \(G\) 存下来,从小到大枚举 \(k\) 来更新 \(G\)。这样每个整除分块点 \(i=\left\lfloor\frac{n}{l......r}\right\rfloor\),只有在 \(p_k^2\le i\) 的时候会被访问,这个复杂度也是 \(O(\frac{n^\frac{3}{4}}{\log n})\) 的,神奇地实现了复杂度平衡。

至于怎么用数组存下所有整除分块点 \(i\),可以分 \(i<\sqrt n\) 的和 \(\left\lfloor\frac{n}{i}\right\rfloor<sqrt n\) 的两种,分别存在一个根号以下的下标。

然后只需要 \(O(\sqrt n)\) 的空间复杂度即可。

另一个要点是递归的时候,由于这部分复杂度分析其实不依赖 \((p,x)\) 对出现次数,所以完全没必要像杜教筛一样开 map 避免重复计算。

尽管跑 n=10000000000 递归的时候一个函数值最多会重复求 600 次

4.洲阁筛

杜教筛套整除分块之后复杂度不变,但是min_25筛就不是。毕竟你 map 去重都没加

需要进行整除分块次min_25筛的话,考虑改变 \(F_k(x)\) 的定义

\(F_k(x)=\sum_{i=1}^x f(x) [i\in P||minp(i)>=p_k]\) ,和求 \(F_p\) 时类似,表示埃氏筛进行到 \(p_{k-1}\) 之后剩下的数。当 \(p_k^2\leq x\) 时,可以类似求 \(F_p\) 反过来,每次加入在 \(k\) 轮中被筛掉而 \(k-1\) 轮中没有删掉的数。直接给出式子

\[F_k(x)=F_{k+1}(x)+\sum_{c=1}^{p_k^{c+1}\leq x} f(p_k^c)(F_{k+1}(x/p_k^c)-F_p(p_k))+f(p_k^{c+1}) \]

边界条件为 \(F_{|P|+1}(x)=F_p(x)\) ,即只剩下质数的情况。

这样用和求 \(F_p\) 一样的递推的代码实现就能求出 \(F_k(x)\)

这次复杂度分析就得用到 \((x,p)\) 对出现的次数了。因为 \(n^{\frac{1}{2}}+n^{\frac{1}{3}}+......\) 其实是 \(\sqrt n\) 级别的,所以这部分复杂度其实和求 \(F_p\) 相同,都是 \(O(\frac{n^\frac{3}{4}}{\log n})\) 的,不过显然常数大了一些。

事实上这个跑 1e11 有点费劲。

5.用法

由于min_25筛会一个一个处理最大质因数大于二次的数这一特点,可以处理最大质因数之类的问题。

posted @ 2026-05-29 21:14  cinccout  阅读(8)  评论(0)    收藏  举报