[BZOJ4805]欧拉函数求和
题目大意:
对于给定的$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)$。
1 #include<cmath> 2 #include<cstdio> 3 #include<cctype> 4 #include<hash_map> 5 typedef long long int64; 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int N=1587402,M=120256; 14 bool vis[N]; 15 int lim,phi[N],p[M]; 16 int64 sum[N]; 17 __gnu_cxx::hash_map<int,int64> map; 18 inline void sieve() { 19 sum[1]=phi[1]=1; 20 for(register int i=2;i<=lim;i++) { 21 if(!vis[i]) { 22 p[++p[0]]=i; 23 phi[i]=i-1; 24 } 25 for(register int j=1;j<=p[0]&&i*p[j]<=lim;j++) { 26 vis[i*p[j]]=true; 27 if(i%p[j]==0) { 28 phi[i*p[j]]=phi[i]*p[j]; 29 break; 30 } 31 phi[i*p[j]]=phi[i]*phi[p[j]]; 32 } 33 sum[i]=sum[i-1]+phi[i]; 34 } 35 } 36 inline int64 calc(const int &n) { 37 if(n<=lim) return sum[n]; 38 if(map.count(n)) return map[n]; 39 int64 ans=(int64)n*(n+1)/2; 40 for(int l=2,r;l<=n;l=r+1) { 41 r=n/(n/l); 42 ans-=calc(n/l)*(r-l+1); 43 } 44 return map[n]=ans; 45 } 46 int main() { 47 const int n=getint(); 48 lim=pow(n,2./3); 49 sieve(); 50 printf("%lld\n",calc(n)); 51 return 0; 52 }
线性筛预处理$S$的前$n^{\frac23}$项,剩下的数论分块计算,用哈希表保存已经算过的值,记忆化搜索即可。时间复杂度$O(n^{\frac23})$。