https://www.lydsy.com/JudgeOnline/problem.php?id=4805
求欧拉函数的前缀和,项数小于2e9。
以目前的视野来看待杜教筛的话,感觉就像是将一个线性的式子,进一步优化,然后通过记忆化搜索来实现的一个过程。
S(n)=∑i=1nϕ(i)
S
(
n
)
=
∑
i
=
1
n
ϕ
(
i
)
然后卷积一下,通过套路式子进行转换。
g(1)S(n)=∑i=1n(g∗ϕ(i))−∑i=2ng(i)S(ni)
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
(
g
∗
ϕ
(
i
)
)
−
∑
i
=
2
n
g
(
i
)
S
(
n
i
)
S(n)=∑i=1ni−∑i=2nS(ni)
S
(
n
)
=
∑
i
=
1
n
i
−
∑
i
=
2
n
S
(
n
i
)
S(n)=n(n+1)2−∑i=2nS(ni)
S
(
n
)
=
n
(
n
+
1
)
2
−
∑
i
=
2
n
S
(
n
i
)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+10;
#define ll long long int
int tot;
ll phi[maxn];
void init()
{
for(ll i=1;i<maxn;i++){
phi[i]=i;
}
for(ll i=2;i<maxn;i++){
if(phi[i]==i){
for(ll j=i;j<maxn;j+=i)
phi[j]-=phi[j]/i;
}
}
for(int i=1;i<maxn;i++){
phi[i]+=phi[i-1];
}
}
map<ll,ll> m;
ll work(ll x){
if(x<maxn) return phi[x];
if(m[x]) return m[x];
ll res=0;
for(ll i=2,j;i<=x;i=j+1){
j=x/(x/i);
res+=(j-i+1)*work(x/i);
}
return m[x]=x*(x+1)/2-res;
}
int main(){
init();
int n;
scanf("%d",&n);
printf("%lld\n",work(n));
return 0;
}