杜教筛模板
记忆化搜索加公式加整数分块
g
(
1
)
∗
s
(
1
)
=
∑
i
=
1
n
h
(
i
)
+
∑
d
=
2
n
g
(
d
)
∗
s
(
⌊
n
d
⌋
)
)
g(1)*s(1)=\sum^{n}_{i=1}h(i)+\sum^{n}_{d=2}g(d)*s(\lfloor \frac{n}{d} \rfloor))
g(1)∗s(1)=∑i=1nh(i)+∑d=2ng(d)∗s(⌊dn⌋))
求
a
n
s
1
=
∑
i
=
1
n
ϕ
(
i
)
ans1=\sum^{n}_{i=1}\phi(i)
ans1=∑i=1nϕ(i)即令g(i)=id(i)即可
化简可得
s
(
n
)
=
∑
i
=
1
n
i
−
∑
d
=
1
n
s
(
⌊
n
d
⌋
)
s(n)=\sum^{n}_{i=1}i-\sum^{n}_{d=1}s(\lfloor \frac{n}{d} \rfloor)
s(n)=∑i=1ni−∑d=1ns(⌊dn⌋)
求
a
n
s
2
=
∑
i
=
1
n
μ
(
i
)
ans2=\sum^{n}_{i=1}\mu(i)
ans2=∑i=1nμ(i)同理
化简可得
s
(
n
)
=
1
−
∑
d
=
2
n
s
(
⌊
n
d
⌋
)
s(n)=1-\sum^{n}_{d=2}s(\lfloor \frac{n}{d} \rfloor)
s(n)=1−∑d=2ns(⌊dn⌋)
#include <bits/stdc++.h>
using namespace std;
using ll = long long ;
const int N = 6000010;
int phi[N],mu[N];
bool vis[N];
ll sum1[N],sum2[N];
void init(int n){
mu[1]=1;
vector<int>pri;
for(int i=2;i<=n;i++){
if(!vis[i]){
mu[i]=-1;
pri.push_back(i);
}
for(int j=0;j<pri.size()&&pri[j]*i<=n;j++){
vis[i*pri[j]]=true;
if(i%pri[j])mu[pri[j]*i]=-mu[i];
else{
mu[pri[j]*i]=0;
break;
}
}
}
pri.clear();
phi[1]=1;
for(int i=2;i<=n;i++){
if(!phi[i]){
pri.push_back(i);
phi[i]=i-1;
}
for(int j=0;j<pri.size()&&i*pri[j]<=n;j++){
if(i%pri[j])phi[i*pri[j]]=phi[i]*phi[pri[j]];
else{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
}
}
for(int i=1;i<=n;i++)
sum1[i]=sum1[i-1]+phi[i],
sum2[i]=sum2[i-1]+mu[i];
}
unordered_map<ll,ll>w1,w2;
ll _1(ll n){
if(n<6000000)return sum1[n];
if(w1[n])return w1[n];
if(n==1)return 1;
ll ans=0;
for(ll l=2,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(r-l+1)*_1(n/l);
}
return w1[n]=(1+n)*n/2-ans;
}
ll _2(ll n){
if(n<6000000)return sum2[n];
if(w2[n])return w2[n];
if(n==1)return 1;
ll ans=0;
for(ll l=2,r;l>=0&&l<=n;l=r+1){
r=n/(n/l);
ans+=(r-l+1)*_2(n/l);
}
return w2[n]=1-ans;
}
int main()
{
init(6000000);
int t;
scanf("%d",&t);
while(t--){
ll n;
scanf("%lld",&n);
printf("%lld %lld\n",_1(n),_2(n));
}
}