杜教筛可以在非线性时间内求积性函数前缀和
比如我们对积性函数(f),我们要求(S(n)=sumlimits^{n}_{i=1}f(i))
先通过构造得积性函数(h)和(g),使得(h=f imes g),并且可以快速计算(h)和(g)的前缀和
[egin{aligned} &sumlimits^{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}
floor) \=&g(1)S(n)+sum_{d=2}^{n}g(d)S(lfloor frac{n}{d}
floor) \&g(1)S(n)=sumlimits^{n}_{i=1}h(i)-sum_{d=2}^{n}g(d)S(lfloor frac{n}{d}
floor) end{aligned}
]
预处理(f)的前(n^{frac{2}{3}})项,后(n^{frac{1}{3}})项递归计算,时间复杂度为(O(n^{frac{2}{3}}))
对于(mu),(μ imes 1=epsilon),构造(g=1,h=epsilon)
对于(varphi),(varphi imes 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;
}