这几天做了几道和杜教筛有关的题目,赶紧记下来怕以后忘了
首先就是最常用的式子
对于一个函数f(x)
设$g(x) =sum_{x|d}f(d)$
但有些时候n很大,这时候O(n)的时间复杂度是不可接受的,我们就需要用杜教筛来处理一些问题
比如$$sum_{i=1}^{N}μ(i)$$
μ有一个性质:$$sum_{d|n}mu(d)=[n=1]$$
于是就有$$sum_{i=1}^{N}sum_{d|i}μ(d) = 1$$
变换一下枚举倍数$$sum_{d=1}^{N}sum_{j = 1}^{[frac{N}{d}]}μ(j) = 1$$
于是 $$sum_{i=1}^{N}μ(i) = 1 - sum_{d=2}^{N}sum_{j = 1}^{[frac{N}{d}]}μ(j)$$
这个式子就可以递归求解了
我们预处理出前1e6的μ的前缀和, 每个$[frac{N}{d}]$都是一个区间,可以一起求出
求前缀和递归函数:
1 int sieve(LL x) 2 { 3 if(x <= MAXN) { 4 return sum[x]; 5 } 6 if(m[x]) { 7 return m[x]; 8 } 9 int S = 1; 10 for(LL i = 2, j; i <= x; i = j + 1) { 11 j = x / (x / i); 12 S = (S - (LL)(j - i + 1) * sieve(x / i) % MOD + MOD) % MOD; 13 } 14 return m[x] = S; 15 }
如果要求$$sum_{i=1}^{N}i*μ(i) $$也可以用同样的方法
根据性质有$$sum_{i=1}^{N}isum_{d|i}μ(d) = 1$$
则$$sum_{i=1}^{N}sum_{d|i}μ(d)*d*frac{i}{d} = 1$$
同样枚举倍数$$sum_{d=1}^{N}dsum_{j=1}^{[frac{N}{d}]}μ(j)*j = 1$$
则$$sum_{i=1}^{N}i*μ(i)=1 - sum_{d=2}^{N}dsum_{i=1}^{[frac{N}{d}]}μ(i)*i $$
做法就与之前相同了
递归函数:
1 inline LL sieve(LL x) 2 { 3 if(x <= 5e6) { 4 return sum[x]; 5 } 6 int hh = get_h(x); 7 if(ha[hh] == x) { 8 return h[hh]; 9 } 10 ha[hh] = x; 11 h[hh] = 1; 12 LL i = 2; 13 while(i <= x) 14 { 15 LL m = x / i, j = x / m; 16 h[hh] = ((LL)h[hh] - (i + j) % MOD * (( j - i + 1) % MOD) % MOD * rev2 % MOD * sieve(m) % MOD + MOD) % MOD; 17 i = j + 1; 18 } 19 return h[hh]; 20 }