• 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
    ",ans);
    }
    
    int main(){
    	init();
        solve(500000000);
    	return 0;	
    }
    

      

  • 相关阅读:
    字节顺序(大端小端)
    动态数组(一维二维)探秘
    算法十正则表达式匹配
    算法九回文数
    算法八字符串转换正数(atoi)
    windows server 2008配置多用户远程连接
    算法七整数反转
    原码反码补码
    算法六Z自形变换
    Java学习笔记之:Java Map集合
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8512709.html
Copyright © 2020-2023  润新知