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;	
}

  

posted @ 2018-03-06 10:02  蒟蒻JHY  阅读(183)  评论(1编辑  收藏  举报