Luogu4213 【模板】杜教筛(Sum)
https://www.luogu.com.cn/problem/P4213
杜教筛
杜教筛核心公式:
\[g(1)S(n)=\sum_{i=1}^n (f*g)(i)-\sum_{i=2}^n g(i)\times S(\lfloor \frac{n}{i} \rfloor) \\
S(n)为答案,g和(f*g)均为易求得的函数,\\
S(\lfloor \frac{n}{i} \rfloor)可以数论分块,并递归求解(记忆化搜索)
\]
\(Part 1:\mu\)
\[根据\mu*I=\epsilon \\
f=\mu,g=I,(f*g)=\epsilon \\
代入求解\\
S(n)=1-\sum_{i=2}^n S(\lfloor \frac{n}{i} \rfloor)
\]
\(Part 2:\varphi\)
\[根据\varphi*I=id \\
f=\varphi,g=I,(f*g)=id \\
代入求解\\
S(n)=\frac{n(n+1)}{2}-\sum_{i=2}^n S(\lfloor \frac{n}{i} \rfloor)
\]
\(C++ Code:\)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#define ll long long
#define N 5000000
using namespace std;
int T;
ll prime[N];
bool pri[N];
int cnt;
ll n,phi[N+10],mu[N+10],sphi[N+10],smu[N+10];
map<ll,ll>ansmu,ansphi;//C++11开unordered_map更快
void Pre()//预处理,优化复杂度
{
phi[1]=mu[1]=1;//开始处理欧拉函数和莫比乌斯函数
for (ll i=2;i<=N;i++)
{
if (!pri[i])
prime[++cnt]=i,phi[i]=i-1,mu[i]=-1;
for (ll j=1;j<=cnt;j++)
{
ll g=i*prime[j];
if (g>N)
break;
pri[g]=true;
if (i%prime[j]==0)
{
phi[g]=phi[i]*prime[j];
mu[g]=0;
break;
}
phi[g]=phi[i]*phi[prime[j]];
mu[g]=mu[i]*mu[prime[j]];
}
}
for (ll i=1;i<=N;i++)//前缀和
{
sphi[i]=sphi[i-1]+phi[i];
smu[i]=smu[i-1]+mu[i];
}
}
ll ans1(ll n)//莫比乌斯函数求解
{
if (n<=N)
return smu[n];
if (ansmu[n])
return ansmu[n];
ll l,r;
ll ans=1;
for (l=2;l<=n;l=r+1)
{
r=n/(n/l);
ans-=(r-l+1)*ans1(n/l);
}
return ansmu[n]=ans;
}
ll ans2(ll n)//欧拉函数求解
{
if (n<=N)
return sphi[n];
if (ansphi[n])
return ansphi[n];
ll l,r;
ll ans=(n+1)*n/2;
for (l=2;l<=n;l=r+1)
{
r=n/(n/l);
ans-=(r-l+1)*ans2(n/l);
}
return ansphi[n]=ans;
}
int main()
{
Pre();
scanf("%d",&T);
while (T --> 0)
{
scanf("%lld",&n);
printf("%lld %lld\n",ans2(n),ans1(n));
}
}