P1 杜教筛能干什么#
给你一个积性函数 f(i),求 f(i) 的前缀和:
n∑i=1f(i)
注意,f(i) 必须是积性函数。
P2 怎么杜教筛#
发现直接求不太行,是 O(n) 的,这样只要 n≤109 就会TLE。
由于满足积性函数,不妨往数论方面想想。
考虑狄利克雷卷积,令 h=f∗g,其中 g(i) 是我们自己根据要求选的函数。h(n) 可以根据定义算出:
h(n)=∑d∣nf(d)g(nd)
再令:
S(n)=n∑i=1f(i)
现在,我们想求 h(n) 的前缀和:
n∑i=1h(i)
怎么办?把定义带进去呗:
n∑i=1h(i)=n∑i=1∑d∣if(d)g(id)
然后发现∑d∣i 有点难办,所以不妨换一个角度思考。我们考虑 q=j⋅k,q≤n,然后是不是 j∣q ,而且贡献是 g(j)f(qj)=g(j)f(k)。
好,现在发现凡是 j 的倍数 q 都能产生有关 g(j) 的贡献,而且是先乘后加的。这个时候就要乘法分配律了:
∑j∣q,q≤ng(j)f(qj)=g(j)⌊nj⌋∑p=1f(p)
好好好,现在再带回去:
n∑i=1h(i)=n∑i=1∑d∣if(d)g(id)=n∑i=1g(i)⌊ni⌋∑p=1f(p)=n∑i=1g(i)S(⌊ni⌋)(1)(2)(3)
现在呢,我们是不是把这个式子化成了有关于三个函数的形式,而且 g 是我们自己定义的,h 是根据 g 来的,所以实际上啊有两个都被我们捏在手里
是不是只用知道 g(1)S(n) 就可以算出 S(n),那么发现可以运用 h 函数的前缀和联系类似于差分的操作得到:
g(1)S(n)=n∑i=1h(i)−n∑i=2h(i)=n∑i=1h(i)−n∑i=2g(i)S(⌊ni⌋)(4)(5)
就得到了核心式子:
g(1)S(n)=n∑i=1h(i)−n∑i=2g(i)S(⌊ni⌋)
为什么要写成这样呢?你看啊,h 是不是被我们控制,那么我们只用合理设置 g 应该就能很快地算出 h 的前缀和以及 g(i) 的值了。
假设 ∑ni=1h(i) 和 g(i) 能 O(1) 算出,那么是不是只剩下
n∑i=2g(i)S(⌊ni⌋)
还是未知的,这个时候发现S(⌊ni⌋)非常符合数论分块的形式啊,那我们就可以递归+数论分块解决。
P3 杜教筛例题#
来看一道模板题:【模板】杜教筛。
这个时候由于 n≤109,而杜教筛可以做到 O(n23) 的,所以可以用杜教筛。
先考虑 ans1 怎么算。
直接算 ∑ni=1ϕ(i) 肯定不行,于是我们想想它有什么性质:
n=∑d∣nϕ(d)
是不是发现可以与一些函数使用狄利克雷卷积了呢?
∑d∣nϕ(d)⋅1(nd)=n=id(n)
那么有 ϕ∗1=id,这个时候直接令 f=ϕ,g=1,h=id 带回去就好了呀:
S(n)=n∑i=1id(i)−n∑i=2S(⌊ni⌋)=n∑i=1i−n∑i=2S(⌊ni⌋)=n⋅(n+1)2−n∑i=2S(⌊ni⌋)(6)(7)(8)
前面部分 O(1) 求,后面部分数论分块。
再看看 ∑ni=1μ(i)。
依旧找性质,考虑莫比乌斯反演:
[n=1]=∑d∣nμ(d)
可以得到:
μ∗1=e
然后可得:
S(n)=1−n∑i=2S(⌊ni⌋)
做完了。
P3 细节#
先算出前面 n23 的前置和,然后利用map进行记忆化搜索。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下