杜教筛&Min_25筛学习笔记
杜教筛
这个东西已经咕了差不多半年QAQ
然后现在才开始写.
有的时候,我们需要完成这样一个问题.
求\(\sum_{i=1}^nf(i)\).其中\(f\)是积性函数.
当\(n\leq 10^7\)时,可以用线性筛解决这个问题.
然而,起源于\(Project Eular\)的这个黑科技可以把\(n\)的范围扩展到\(10^{11}\)左右.
考虑狄利克雷卷积.
假设\(f*g=h\),那么写成狄利克雷卷积的形式,就是
\[\sum_{i=1}^nh(i)=\sum_{i=1}^n\sum_{d|i}f(i)g(\frac{i}{d})\\
=\sum_{d=1}^ng(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f(i)\\
=\sum_{d=1}^ng(d)S(\lfloor\frac{n}{d}\rfloor)\\
把第一项拉出来,得\\
g(1)S(n)=\sum\limits_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)-\sum\limits_{i=2}^{n}g(i)S(\lfloor\frac{n}{i} \rfloor)
\]
考虑到\(\lfloor\frac{n}{d}\rfloor\)只有\(\sqrt n\)种取值,于是记忆化搜索一波,美滋滋.
因此,只要可以快速求\(h\)的前缀和与\(g\),就可以快速求\(f\)的和.
时间复杂度大约是\(O(n^{\frac{3}{4}})\),可以用积分证.
下面举几个栗子.
莫比乌斯函数
我们知道\(\mu*1=e\),而\(\sum h=1\),因此就很好求啦.
在存储上也有一个小优化,无需\(map\).考虑到求出的每个\(S(x)\),\(x\)都是\(n\)的因数且\(\frac{n}{x}\)不大,因此只需如下代码即可.
LL calc_miu(int x){
if(x<maxn)return miu[x];
else if(w2[n/x])return w2[n/x];
LL ans=1;
for(int i=2,ed;i<=x;i=ed+1)
ed=x/(x/i),ans-=(ed-i+1)*calc_miu(x/i);
return w2[n/x]=ans;
}
欧拉函数
我们知道\(\varphi*1=id\),因此\(\sum h=\frac{n*(n-1)}{2}\),就很好求啦.
代码如下
LL calc_phi(int x){
if(x<maxn)return phi[x];
else if(w1[n/x])return w1[n/x];
LL ans=(LL)x*(LL)(x+1)/2;
for(int i=2,ed;i<=x;i=ed+1)
ed=x/(x/i),ans-=(ed-i+1)*calc_phi(x/i);
return w1[n/x]=ans;
}
Min_25筛
待UPD