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