[BZOJ3944]Sum
题目大意:
对于给定的$n(n<2^{31})$,求$\sum_{i=1}^n\varphi(i)$和$\sum_{i=1}^n\mu(i)$。
思路:
$\sum_{i=1}^n\varphi(i)$同BZOJ4805。
设$S(n)=\sum_{i=1}^n\mu(i)$。
因为$\sum_{d|n}\mu(d)=[n=1]$,$S(n)=\sum_{i=1}^n([i=1]-\sum_{d|i,d<i}\mu(d))=1-\sum_{i=2}^nS(\lfloor\frac ni\rfloor)$。
线性筛预处理$S$的前$n^{\frac23}$项,剩下的数论分块计算,用哈希表保存已经算过的值,记忆化搜索即可。时间复杂度$O(n^{\frac23})$。
细节:
两个询问必须写在一个函数里,否则会TLE。
1 #include<cstdio> 2 #include<cctype> 3 #include<hash_map> 4 typedef long long int64; 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=1664511,M=125640; 13 bool vis[N]; 14 int m,mu[N],phi[N],p[M]; 15 int64 s_mu[N],s_phi[N]; 16 __gnu_cxx::hash_map<int,std::pair<int64,int64> > map; 17 inline void sieve() { 18 phi[1]=mu[1]=s_phi[1]=s_mu[1]=1; 19 for(register int i=2;i<N;i++) { 20 if(!vis[i]) { 21 p[++p[0]]=i; 22 mu[i]=-1; 23 phi[i]=i-1; 24 } 25 for(register int j=1;j<=p[0]&&i*p[j]<N;j++) { 26 vis[i*p[j]]=true; 27 if(i%p[j]==0) { 28 mu[i*p[j]]=0; 29 phi[i*p[j]]=phi[i]*p[j]; 30 break; 31 } 32 mu[i*p[j]]=-mu[i]; 33 phi[i*p[j]]=phi[i]*phi[p[j]]; 34 } 35 s_mu[i]=s_mu[i-1]+mu[i]; 36 s_phi[i]=s_phi[i-1]+phi[i]; 37 } 38 } 39 inline std::pair<int64,int64> calc(const int64 &n) { 40 if(n<N) return std::make_pair(s_phi[n],s_mu[n]); 41 if(map.count(n)) return map[n]; 42 std::pair<int64,int64> ans=std::make_pair((int64)n*(n+1)/2,1); 43 for(register int64 l=2,r;l<=n;l=r+1) { 44 r=n/(n/l); 45 std::pair<int64,int64> tmp=calc(n/l); 46 ans.first-=tmp.first*(r-l+1); 47 ans.second-=tmp.second*(r-l+1); 48 } 49 return map[n]=ans; 50 } 51 int main() { 52 sieve(); 53 for(register int T=getint();T;T--) { 54 std::pair<int64,int64> ans=calc(getint()); 55 printf("%lld %lld\n",ans.first,ans.second); 56 } 57 return 0; 58 }