杜教筛
Posted hnylmstea
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杜教筛相关的知识,希望对你有一定的参考价值。
快速求一个积性函数 (f) 的前缀和,
记为 (S)
[S(n)=sum_{i=1}^{n} f(i)]
考虑一个积性函数 (g)
[ egin{aligned} & sum_{i=1}^{n}(f*g)(i) =& sum_{i=1}^{n}sum_{d|n}^{i}f(d)g(frac{i}{n}) =& sum_{d=1}^ng(d)sum_{i=1}^{frac{n}{d}}f(i) =& sum_{d=1}^{n}g(d)S(frac{n}{d}) =& sum_{d=2}^ng(d)S(frac{n}{d})+g(1) imes S(n) end{aligned} ]
所以我们得到了最重要的式子:
[ g(1)S(n)=sum_{i=1}^{n}(f*g)(i)-sum_{d=2}^ng(d)S(frac{n}{d}) ]
所以我们只要构造出一个 (g) ,我们能快速求出它的前缀和以及 (f * g) 的前缀和,那么对后面的整数分块, 复杂度 (O(n^{frac{3}{4}})) , 如果预处理到 (5e6), 复杂度近似为 (O(n^{frac{2}{3}}))。
伪代码:
ll GetSum(int n) { // 算 f 前缀和的函数
//记忆化
ll ans = sum( (f * g)(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 Sum(n) = ans;//记忆化
}
常用公式:
[mu * 1 = epsilon]
[varphi * 1=Id]
一个小小的拓展:
求 (sum_{i=1}^nvarphi(i) imes i)
首先来了解一个结论:
[(varphi imes Id) * Id=n^2]
(手推一下)
这题就是求 (f=varphi imes Id) 的前缀和,
令 (g=Id)
[g(1)S(n)=sum_{i=1}^n(f*g)(i)-sum_{d=2}^ng imes S(frac{n}{d})]
[(f*g)(n)=n^2]
((f*g)(n)) 的前缀和为 (frac{n(n+1)(2n+1)}{6}).
然后就可以筛了。
以上是关于杜教筛的主要内容,如果未能解决你的问题,请参考以下文章