题意:
给定n,求欧拉函数前n项和。
数据范围:n<=2e9
解法:
欧拉函数性质:
∑
d
∣
n
φ
(
d
)
=
n
\sum_{d|n}φ(d)=n
∑d∣nφ(d)=n
转化为卷积形式:
φ
∗
I
=
i
d
φ*I=id
φ∗I=id
杜教筛递推式:
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
(
f
∗
g
)
(
i
)
−
∑
i
=
2
n
g
(
i
)
S
(
⌊
n
i
⌋
)
g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^ng(i)S(\lfloor \frac ni \rfloor)
g(1)S(n)=∑i=1n(f∗g)(i)−∑i=2ng(i)S(⌊in⌋)
令
f
=
φ
,
g
=
I
f=φ,g=I
f=φ,g=I,上式变为:
S
(
n
)
=
n
∗
(
n
+
1
)
2
−
∑
i
=
2
n
S
(
⌊
n
i
⌋
)
S(n)=\frac {n*(n+1)}{2}-\sum_{i=2}^nS(\lfloor \frac ni \rfloor)
S(n)=2n∗(n+1)−∑i=2nS(⌊in⌋)
前半部分O(1)计算,后半部分整除分块递归计算。
code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxm=1e6+5;
ll phi[maxm];
ll notprime[maxm];
ll prime[maxm],cnt;
ll sum_phi[maxm];
void init(){
phi[1]=1;
for(int i=2;i<maxm;i++){
if(!notprime[i]){
prime[cnt++]=i;
phi[i]=i-1;
}
for(int j=0;j<cnt;j++){
if(prime[j]*i>=maxm)break;
notprime[prime[j]*i]=1;
phi[prime[j]*i]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
if(i%prime[j]==0)break;
}
}
for(int i=1;i<maxm;i++){
sum_phi[i]=sum_phi[i-1]+phi[i];
}
}
map<ll,ll>mp_phi;
ll S_phi(ll x){
if(x<maxm)return sum_phi[x];
if(mp_phi[x])return mp_phi[x];
ll ans=x*(x+1)/2;
for(ll i=2,j;i<=x;i=j+1){
j=x/(x/i);
ans-=S_phi(x/i)*(j-i+1);
}
return mp_phi[x]=ans;
}
signed main(){
init();
ll n;scanf("%lld",&n);
printf("%lld\n",S_phi(n));
return 0;
}