poj2478/luogu3601欧拉函数的和。

poj2478,poj3090=sdoi仪仗队,还有洛谷3601题意接近,数据范围不同。

poj2478,求10^6内所有数的欧拉函数的和。用欧拉筛直接求素数和欧拉函数即可。

参考代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const int MAXL=1e6+10;
long long prime[MAXL],phi[MAXL],ans[MAXL];
bool  isnot_pr[MAXL];
//欧拉,p素数,phi(p)=p-1;
//gcd(i,j)==1 phi(i,j)=phi(i)*phi(j);
//i%p==0 phi(i*p)=p*phi(i);else phi(i*p)=phi(p)*phi(i)=(p-1)*phi(i); 
int work() {
	int tot = 0;
	for (int i = 2; i < MAXL; ++i) {
		if (!isnot_pr[i])phi[i]=i-1,prime[tot++] = i;
		for (int j = 0; j < tot; ++j) {
			if (i * prime[j] > MAXL) break;
			isnot_pr[i*prime[j]] = 1;
			phi[i*prime[j]]=phi[i]*(prime[j]-1); 
			if (i % prime[j] == 0) {
				phi[i*prime[j]]=phi[i]*prime[j]; break; 
			}	 
		}
		ans[i]=ans[i-1]+phi[i];
	}
}
int main() {
	int x=1;
	work();
	while(x){
		scanf("%d",&x);
		printf("%lld",ans[x]);
	}
	
}

洛谷3601,a,b数据范围到10^12,需要求a-b内所有欧拉函数的和。前面求sqrt(b)范围内的所有素数再加一个.sqrt(b)的素数,大约,有8000个和前面的方法是一样的。 如果枚举[a,b]中每个数字,分别求其欧拉函数,复杂度10^6*8000.我们反过来,枚举素数表内的每个素数,通过算式,每次+prime【i】直接找到包含这个素数因子的数。事件复杂度为(n/2+n/3+n/5+……类似与筛法求素数nlogn的时间复杂度。(不太会算),在这种枚举的过程中,没有无效查找。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<math.h>
using namespace std;

const int MAXL=1e6+10;
const long long MD=666623333;
long long prime[MAXL],phi[MAXL],vis[MAXL];
long long ans[MAXL];
bool  isnot_pr[MAXL];
int tot = 0; 
int work(long long y) {
    long long t=sqrt(y);
    for (long long i = 2; i <=t; ++i) {
        if (!isnot_pr[i])
            prime[tot++] = i;	
        for (int j = 0; j < tot; ++j) {
            if (i * prime[j] >t) break;
            isnot_pr[i*prime[j]] = 1;
            if (i % prime[j] == 0) break; 	 
        }
    }
    for(int i=0;i<tot;i++)
        while(y%prime[i]==0)y/=prime[i];
    prime[tot++]=y; 
    cout<<tot<<" "<<prime[tot-2]<<" "<<prime[tot-1]<<endl;
}
void  ph(long long x,long long y){
    long long t=y-x,l=x;
    for(int i=0;i<=t;i++)phi[i]=x+i,vis[i]=phi[i];//vis存储不断约掉质因子后的值。
    for(int i=0;i<tot;i++){  
    //找出l,r中j=prime[i]的倍数y,做好 phi[y]=y/j*j-1';
        l=x;
        if(prime[i]*prime[i]>y)break;
        if(l%prime[i]!=0)l=l+(prime[i]-l%prime[i]);
        for(int j=l-x;j<=y-x;j+=prime[i]){
            phi[j]=phi[j]/prime[i]*(prime[i]-1);
            while(vis[j]%prime[i]==0)vis[j]/=prime[i];
        }
    }
    for(int i=0;i<=t;i++)
        if(vis[i]>1)phi[i]=phi[i]/vis[i]*(vis[i]-1);
}
int main() {
    long long x,y,tmp=0,t;
    
    scanf("%lld%lld",&x,&y);
    t=y-x;
    work(y);	
    ph(x,y);
    for(int i=0;i<=t;i++)
        tmp=(tmp+x+i-phi[i])%MD;
    printf("%lld\n",tmp); 
}



猜你喜欢

转载自blog.csdn.net/lengxuenong/article/details/79471667