杜教筛#
用来在非线性时间内求积性函数前缀和
设现在要求积性函数 f 的前缀和, 设 n∑i=1f(i)=S(n)。
再找一个积性函数 g ,则考虑它们的狄利克雷卷积的前缀和
n∑i=1(f∗g)(i)
=n∑i=1∑d|if(d)g(id)=n∑d=1g(d)⌊nd⌋∑i=1f(i)=n∑d=1g(d)S(⌊nd⌋)
再考虑一个式子
g(1)S(n)=n∑i=1g(i)S(⌊ni⌋)−n∑i=2g(i)S(⌊ni⌋)
所以得到杜教筛的核心式子:
g(1)S(n)=n∑i=1(f∗g)(i)−n∑i=2g(i)S(⌊ni⌋)
找到一个合适的积性函数 g ,使得可以快速算出 n∑i=1(f∗g)(i) 和 g 的前缀和,便可以用数论分块递归地求解。
inline int F_sum(int n){
if(n <= 5e6) return f[n];
int &sum = n <= m ? F[n] : F[m + ::n / n];
if(sum) return sum; sum = FG_sum(n);
for(int l(2), r; l <= n; l = r + 1)
r = n / (n / l), sum -= (G_sum(r) - G_sum(l - 1)) * F_sum(n / l);
return sum;
}
-
记忆化:
上面的求和过程中出现的都是 ⌊ni⌋ 。开一个大小为两倍 √n 的数组 dp 记录答案。
若 x≤√n ,返回 dp[x]
,否则返回 dp[sqrt n + n / x]
即可。
-
杜教筛的重点是对于要求的 f,找到 (f∗g),满足 g,(f∗g) 的前缀和都很好求出,如果没办法背下常见的狄利克雷卷积结果,不妨直接枚举几个情况试试,来两例子:
- f(n)=μ(n)n2,g(n)=n2,(f∗g)(n)=[n=1];
- f(n)=φ(n)n2,g(n)=n2,(f∗g)(n)=n3;
DZY Loves Math IV
开始在想能不能把 i 和 j 分开
因为 n≤105,m≤109,所以比较自然地想到枚举 n 去求解,然后开始考虑对某一个 n 怎么处理。
因为 φ 函数的一些性质:n=∏qi=1pcii,φ(n)=φ(∏qi=1pi)∏qi=1pci−1i
考虑先把 n 的质因数次数高于一次的部分都提出来,记为 x,剩下的 nx 记为 y.
m∑i=1φ(ni)=xm∑i=1φ(yi)=xm∑i=1φ(ygcd(y,i))φ(i)gcd(y,i)=xm∑i=1φ(ygcd(y,i))φ(i)∑j∣gcd(y,i)φ(j) (这里用的是 n=∑i∣nφ(i))=xm∑i=1φ(i)∑j∣gcd(y,i)φ(yj) (由于 y 的特殊性,y 与 gcd(y,i) 的因数互质,可以直接乘)=xm∑i=1φ(i)∑j∣y,j∣iφ(yj) (然后对枚举顺序进行一个交换)=x∑j∣yφ(yj)mj∑i=1φ(ji) (整理到此处于是可以递归)
总之记忆化后,复杂度是对的.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下