您的位置:首页 > 其它

[BZOJ4805]欧拉函数求和

2018-02-26 14:40 399 查看

题目大意:
  对于给定的$n(n\leq2\times10^9)$,求$\sum_{i=1}^n\varphi(i)$。

思路:
  设$S(n)=\sum_{i=1}^n\varphi(i)$。
  因为$\sum_{d|n}\varphi(d)=n$,$S(n)=\sum_{i=1}^n(i-\sum_{d|i,d<i}\varphi(d))=\frac{n(n+1)}2-\sum_{i=2}^nS(\lfloor\frac ni\rfloor)$。
  

#include<cmath>
#include<cstdio>
#include<cctype>
#include<hash_map>
typedef long long int64;
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=1587402,M=120256;
bool vis
;
int lim,phi
,p[M];
int64 sum
;
__gnu_cxx::hash_map<int,int64> map;
inline void sieve() {
sum[1]=phi[1]=1;
for(register int i=2;i<=lim;i++) {
if(!vis[i]) {
p[++p[0]]=i;
phi[i]=i-1;
}
for(register int j=1;j<=p[0]&&i*p[j]<=lim;j++) {
vis[i*p[j]]=true;
if(i%p[j]==0) {
phi[i*p[j]]=phi[i]*p[j];
break;
}
phi[i*p[j]]=phi[i]*phi[p[j]];
}
sum[i]=sum[i-1]+phi[i];
}
}
inline int64 calc(const int &n) {
if(n<=lim) return sum
;
if(map.count(n)) return map
;
int64 ans=(int64)n*(n+1)/2;
for(int l=2,r;l<=n;l=r+1) {
r=n/(n/l);
ans-=calc(n/l)*(r-l+1);
}
return map
=ans;
}
int main() {
const int n=getint();
lim=pow(n,2./3);
sieve();
printf("%lld\n",calc(n));
return 0;
}

 

线性筛预处理$S$的前$n^{\frac23}$项,剩下的数论分块计算,用哈希表保存已经算过的值,记忆化搜索即可。时间复杂度$O(n^{\frac23})$。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: