杜教筛
杜教筛可以在非线性时间内求积性函数前缀和
比如我们对积性函数\(f\),我们要求\(S(n)=\sum\limits^{n}_{i=1}f(i)\)
先通过构造得积性函数\(h\)和\(g\),使得\(h=f \times g\),并且可以快速计算\(h\)和\(g\)的前缀和
\[\begin{aligned} &\sum\limits^{n}_{i=1}h(i) \\ =&\sum_{i=1}^{n}\sum_{d \mid i}f(\frac{i}{d})g(d) \\ =&\sum_{d=1}^{n}g(d)S(\lfloor \frac{n}{d} \rfloor) \\=&g(1)S(n)+\sum_{d=2}^{n}g(d)S(\lfloor \frac{n}{d} \rfloor) \\&g(1)S(n)=\sum\limits^{n}_{i=1}h(i)-\sum_{d=2}^{n}g(d)S(\lfloor \frac{n}{d} \rfloor) \end{aligned}
\]
预处理\(f\)的前\(n^{\frac{2}{3}}\)项,后\(n^{\frac{1}{3}}\)项递归计算,时间复杂度为\(O(n^{\frac{2}{3}})\)
对于\(\mu\),\(μ \times 1=\epsilon\),构造\(g=1,h=\epsilon\)
对于\(\varphi\),\(\varphi \times 1=id\),构造\(g=1,h=id\)
\(code:\)
void init()
{
mu[1]=phi[1]=1;
for(ll i=2;i<=all;++i)
{
if(!tag[i]) pri[++tot]=i,mu[i]=-1,phi[i]=i-1;
for(ll j=1;j<=tot;++j)
{
ll k=i*pri[j];
if(k>all) break;
tag[k]=true;
if(i%pri[j]) mu[k]=mu[i]*mu[pri[j]],phi[k]=phi[i]*phi[pri[j]];
else
{
mu[k]=0,phi[k]=phi[i]*pri[j];
break;
}
}
}
for(int i=1;i<=all;++i) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}
ll getphi(ll n)
{
if(n<=all) return phi[n];
if(s_phi[n]) return s_phi[n];
ll ans=n*(n+1)/2;
for(int l=2,r;l<=n;l=r+1)
r=n/(n/l),ans-=(r-l+1)*getphi(n/l);
return s_phi[n]=ans;
}
ll getmu(ll n)
{
if(n<=all) return mu[n];
if(s_mu[n]) return s_mu[n];
ll ans=1;
for(int l=2,r;l<=n;l=r+1)
r=n/(n/l),ans-=(r-l+1)*getmu(n/l);
return s_mu[n]=ans;
}