杜教筛
这是一个玄学的东西……
杜教筛能够在$O(n^{\frac{2}{3}})$内算出积性函数的前缀和
原理:
对于一个积性函数,要求
$$S(n)=\sum_{i=1}^n f(i)$$
需要根据函数 $f(n)$ 的性质,构造一个 $S(n)$ 关于 $S(\lfloor\frac{n}{i}\rfloor)$ 的递推式,如下例。
找到一个合适的数论函数 $g(n)$:
$$\sum_{i=1}^n\sum_{d|i}f(d)g\Big(\frac{i}{d}\Big)=\sum_{i=1}^n g(i)S(\lfloor\frac{n}{i}\rfloor)$$
可以得到递推式:
$$g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^n g(i)S(\lfloor\frac{n}{i}\rfloor)$$
$f*g$ 为狄利克雷卷积,$(f*g)(x)=\sum_{d|n}f(d)g(\frac{n}{d})$
时间复杂度,不会证啊!QAQ 你只要知道它很快就好了。
假如可以快速对 $(f*g)(i)$ 以及 $g(i)$ 完成求和,那么就可以根据的$\lfloor\frac{n}{i}\rfloor$取值进行分段,计算一个 $S(n)$ 的复杂度即为 $O(\sqrt{n}) $。
参见博客戳这里。
实现:
很容易想到记忆化深搜,然后用 map 存值,代码如下:
1 int get_mu(int x){ 2 if(x<=1700000)return mu1[x]; 3 if(mu2.count(x))return mu2[x]; 4 int ans=1; 5 for(int i=2,pos;i<=x;i=pos+1){ 6 pos=x/(x/i); 7 ans-=get_mu(x/i)*(pos-i+1); 8 } 9 return mu2[x]=ans; 10 }
先用线性筛求出 $n^{\frac{2}{3}}$ 的前缀和可以降低时间复杂度!