PE 512 Sums of totients of powers
可以很简单的发现,当n是奇数的时候,f(n)=φ(n),否则f(n)=0。
所以我们就是求n<=5*10^8且n为奇数的φ的和。
首先我们可以做到用杜教筛算出φ的前缀和,但是如何把偶数的减去?
我们设h(x)为1<=n<=x且n为偶数的φ的和,可以得到: h(x)=Σ(1<=i<=x/2) φ(i) + h(x/2)。
为什么这样是对的呢?
考虑一个偶数n,它在2这个质因子上的指数可能是1或者大于1两种情况。
如果指数是是1的话那么φ(n)=φ(n/2) 否则φ(n)=φ(n/2)*2。
我们显然可以先把所有偶数在2上的指数都当成1,先加上 φ的前缀和,然后再把少加的加上。
显然只有一个偶数/2之后还是偶数才需要再加上一遍他的φ,因为只有这样它在2的次数才>1。
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1000000; using namespace std; int zs[maxn/5],t=0; map<int,ll> mmp; bool v[maxn+5]; ll phi[maxn+5]; inline void init(){ phi[1]=1; for(int i=2;i<=maxn;i++){ if(!v[i]) zs[++t]=i,phi[i]=i-1; for(int j=1,u;j<=t&&(u=zs[j]*i)<=maxn;j++){ v[u]=1; if(!(i%zs[j])){ phi[u]=phi[i]*zs[j]; break; } phi[u]=phi[i]*(zs[j]-1); } } for(int i=1;i<=maxn;i++) phi[i]+=phi[i-1]; } inline ll getphi(int x){ if(x<=maxn) return phi[x]; if(mmp.count(x)) return mmp[x]; ll an=x*(ll)(x+1)>>1ll; for(int i=2,j,now;i<=x;i=j+1){ now=x/i,j=x/now; an-=(j-i+1)*getphi(now); } mmp[x]=an; return an; } inline void solve(int x){ ll ans=getphi(x); x>>=1; while(x) ans-=getphi(x),x>>=1; printf("%lld\n",ans); } int main(){ init(); solve(500000000); return 0; }
我爱学习,学习使我快乐