浅谈杜教筛
Gypsophila · · 题解
杜教筛模板
杜教筛是用来干蛤的呢?
它可以在非线性时间内求积性函数前缀和。
前置知识
积性函数
积性函数:对于任意互质的整数
完全积性函数:对于任意整数
- 常见的积性函数:
\varphi,\mu,\sigma,d - 常见的完全积性函数:
\epsilon,I,id
这里特殊解释一下
狄利克雷卷积
设
性质:满足交换律,结合律
单位元:
结合狄利克雷卷积得到的几个性质:
-
\mu * I = \epsilon -
\varphi * I = id -
\mu * id = \varphi
莫比乌斯反演
若
则
证明:这里需要用到前面提到的性质:
给出的条件等价于
所以
杜教筛
设现在要求积性函数
再找一个积性函数
其中得到第一行是根据狄利克雷卷积的定义。
得到第二行则是先枚举
得到第三行则是把
接着考虑
可以发现,他就等于
(可以理解成从1开始的前缀和减去从2开始的前缀和就是第一项)
前面这个式子
所以得到杜教筛的核心式子:
得到这个式子之后有什么用呢?
现在如果可以找到一个合适的积性函数
代码按照理解大概可以写成这样(默认 ll
为 long long
)
(可以理解成一个伪代码。。就是一个思路的框架)
ll GetSum(int n) { // 算 f 前缀和的函数
ll ans = f_g_sum(n); // 算 f * g 的前缀和
// 以下这个 for 循环是数论分块
for(ll l = 2, r; l <= n; l = r + 1) { // 注意从 2 开始
r = (n / (n / l));
ans -= (g_sum(r) - g_sum(l - 1)) * GetSum(n / l);
// g_sum 是 g 的前缀和
// 递归 GetSum 求解
} return ans;
}
这个代码的复杂度是
设求出
还可以进一步优化杜教筛,即先线性筛出前
当
可以使用哈希表来存下已经求过的答案,也可以不用。
考虑到上面的求和过程中出现的都是 GetSum(x)
,若 dp[x]
,否则返回 dp[sqrt n + n / i]
即可。这样可以省去哈希表的复杂度。
实战演练
再挂一次核(tao)心(lu)式,全都要靠它:
它的关键就是要找到合适的
理论知识大概就这么多,接下来看几个例子:
(1) \mu 的前缀和
考虑到莫比乌斯函数的性质
其中
所以就轻松的解决了。
杜教筛代码:
inline ll GetSumu(int n) {
if(n <= N) return sumu[n]; // sumu是提前筛好的前缀和
if(Smu[n]) return Smu[n]; // 记忆化
ll ret = 1ll; // 单位元的前缀和就是 1
for(int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l); ret -= (r - l + 1) * GetSumu(n / l);
// (r - l + 1) 就是 I 在 [l, r] 的和
} return Smu[n] = ret; // 记忆化
}
(2) \varphi 的前缀和
考虑到
杜教筛代码:
inline ll GetSphi(int n) {
if(n <= N) return sump[n]; // 提前筛好的
if(Sphi[n]) return Sphi[n]; // 记忆化
ll ret = 1ll * n * (n + 1) / 2; // f * g = id 的前缀和
for(int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l); ret -= (r - l + 1) * GetSphi(n / l);
// 同上,因为两个的 g 都是 I
} return Sphi[n] = ret; // 记忆化
}
(1) & (2) 就是杜教筛模板 luogu p4213
(3) (综合)\sum\limits_{i=1}^{n}\varphi(i) \cdot i
令
即
这样就可以快速求得
就可以了。
题目
先推荐洛谷模板题
还有一题 luoguP3768 简单的数学题,这道题推完式子可以用杜教筛来求
51nod 上也有很多杜教筛的题目,放几个:
- 51nod 1244
- 51nod 1237
- 51nod 1238
- 51nod 1239
- 51nod 1220
- ...