筛法
冷静分析:CMD 的博客
线性筛
线性筛是个好东西。一般来说,可以在 O(n) 内处理几乎所有的积性函数。
还可以 O(n) 找出所有的质数……(废话
杜教筛
放在偏序关系 (Z,|) 中卷积……
如何快速的求 S(n)=∑ni=1f(i)。
如果能够找到一个函数 g :
n∑i=1(f∗g)(i)=n∑i=1∑d|if(id)g(d)=n∑d=1g(d)⌊nd⌋∑i=1f(i)=n∑d=1g(d)S(⌊nd⌋)
那么可以得出:
g(1)S(n)=n∑i=1(f∗g)(i)−n∑d=2g(d)S(⌊nd⌋)
这样我们就可以通过整除分块快速的求出 g(1)S(n) 了。
当然,需要有很严苛的前提:
其时间复杂度大概是在 O(n23) 的,如果不预处理小块的话应该是 O(n34) 的。
例题:
-
快速求 ∑ni=1∑nj=1φ(gcd(i,j))
-
快速求 ∑ni=1∑nj=1i⋅j⋅gcd(i,j)
例二中有一个很好的东西,点乘。
其定义有:(f⋅g)(n)=f(n)⋅g(n)。
当 h 为完全积性函数时,有 (f⋅h)∗(g⋅h)=(f∗g)⋅h。
这里列出一些基本的组合:
Min25 筛
本质是对线性筛的扩展……
为了方便,声明一些符号:
还是求 ∑ni=1f(i)。可以用 Min25 筛需要满足一些条件:
-
f(i) 是一个低阶多项式。
-
f(pk) 可以快速的求解。
现在考虑把每一阶分别计算。
TODO
PN 筛
首先定义 Powerful Number
。
一个数是 Powerful Number
当其质因数分解中 n=∏ki=1pcii,∀i(ci>1)。
由于一个 Powerful Number
可以表示为一个数的平方和一个数的立方,所以 n 以内的 PN 数一共有 O(√n) 个。
现在假设要求 F(n)=∑ni=1f(i)。
需要找到函数 g 满足:
记 G(n)=∑ni=1g(n)。
先构造函数 h 满足 h∗g=f。
于是将卷积展开:
F(n)=n∑i=1f(i)=n∑i=1∑d|ih(d)g(id)=n∑d=1⌊nd⌋∑i=1h(d)g(i)=n∑d=1h(d)⌊nd⌋∑i=1g(i)=n∑d=1h(d)G(⌊nd⌋)
怎么可以套数论分块?
由于积性函数相乘任然为积性函数,所以可知 h(1)=1。
所以对于质数 p,有 f(p)=g(1)h(p)+g(p)h(1)=h(p)+g(p)。
由于 f(p)=g(p),所以可知 h(p)=0。
根据积性函数的性质,可以推导出 h(n) 只在 n 为 PN
数的时候才可能不为 0。
所以原式变为:
F(n)=n∑d is PNh(d)G(⌊nd⌋)
这样,我们只需要求出 O(√n) 个 h(d) 的取值,以及快速算出 G(x) 的取值即可。
那么我们考虑如何求解 h(d)?
根据 f=g∗h 有
f(pc)=c∑i=0g(pi)h(pc−i)
稍微移项可以得到:
g(1)h(pc)=f(pc)−c∑i=1g(pi)h(pc−i)↓h(pc)=f(pc)−c∑i=1g(pi)h(pc−i)
于是可以枚举所有的 p 以及 c 求出 h(pc) 即可。
此时 p 的个数视作 O(√n),而 c 的界为 O(logn),有由于是 logn 转移,所以这部分复杂度为 O(√nlogn2),而且这个上界很宽松。
但是如果我们直接推导出 h(pc) 仅与 pc 有关的计算公式,那么可能更加优秀,复杂度一般为 O(√nlogn)。
所以总的复杂度一般为 O(√n+√nlogn)=O(√nlogn)。非常的优秀。
然而根据 CMD 的博客,硬上的复杂度实际上是 O(√n/logn)……更加优秀了。
不过有些情况下,利用 PN 筛可能需要套一个杜教筛,毕竟我们除了 h(pc) 还需要求出 G(x) 的前缀和。
此时需要加上杜教筛的复杂度,可以认为是 O(n23) 的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?