小奇学数论
时间限制: 1 Sec 内存限制: 128 MB题目描述
小奇在数论课上学习了素数判定算法,但它不满⾜于此!
求小于等于n的素数个数。
求小于等于n的素数个数。
输入
输⼊1个数字n。
输出
输出1个整数,表示答案。
提示
对于20%的数据,1≤n≤104
对于40%的数据,1≤n≤106
对于60%的数据,1≤n≤107
对于80%的数据,1≤n≤108
对于100%的数据,1≤n≤1011
对于40%的数据,1≤n≤106
对于60%的数据,1≤n≤107
对于80%的数据,1≤n≤108
对于100%的数据,1≤n≤1011
题解
一言不合粘板子,Meisell-Lehmer算法。
1 #include<cmath> 2 #include<cstdio> 3 #include<iostream> 4 #define IL inline 5 #define RG register 6 using namespace std; 7 typedef long long LL; 8 const int N=5000005; 9 const int M=7; 10 const int PM=2*3*5*7*11*13*17; 11 int p[N],pi[N]; 12 int phi[PM+1][M+1],sz[M+1]; 13 LL n; 14 bool f[N]; 15 IL void getprime() 16 { 17 for(RG int i=2;i<N;i++) 18 { 19 if(!f[i]) 20 p[++p[0]]=i; 21 pi[i]=p[0]; 22 for(RG int j=1;p[j]*i<N;j++) 23 { 24 f[p[j]*i]=1; 25 if(i%p[j]==0) 26 break; 27 } 28 } 29 } 30 IL void init() 31 { 32 getprime(); 33 sz[0]=1; 34 for(RG int i=0;i<=PM;i++) 35 phi[i][0]=i; 36 for(RG int i=1;i<=M;i++) 37 { 38 sz[i]=p[i]*sz[i-1]; 39 for(RG int j=1;j<=PM;j++) 40 phi[j][i]=phi[j][i-1]-phi[j/p[i]][i-1]; 41 } 42 } 43 IL int sqrt2(LL x) 44 { 45 LL r=(LL)sqrt(x-0.1); 46 while(r*r<=x) r++; 47 return (int)(r-1); 48 } 49 IL int sqrt3(LL x) 50 { 51 LL r=(LL)cbrt(x-0.1); 52 while(r*r*r<=x) r++; 53 return (int)(r-1); 54 } 55 IL LL getphi(LL x,int s) 56 { 57 if(s==0) return x; 58 if(s<=M) return phi[x%sz[s]][s]+(x/sz[s])*phi[sz[s]][s]; 59 if(x<=p[s]*p[s]*p[s]&&x<N) 60 { 61 int s2x=pi[sqrt2(x)]; 62 LL ans=pi[x]-(s2x+s-2)*(s2x-s+1)/2; 63 for(RG int i=s+1;i<=s2x;i++) 64 ans+=pi[x/p[i]]; 65 return ans; 66 } 67 return getphi(x,s-1)-getphi(x/p[s],s-1); 68 } 69 IL LL getpi(LL x) 70 { 71 if(x<N) return pi[x]; 72 LL ans=getphi(x,pi[sqrt3(3)])+pi[sqrt3(x)]-1; 73 for(RG int i=pi[sqrt3(x)]+1,ed=pi[sqrt2(x)];i<=ed;i++) 74 ans-=getpi(x/p[i])-i+1; 75 return ans; 76 } 77 LL MeiLeh(LL x) 78 { 79 if(x<N) return pi[x]; 80 int a=(int)MeiLeh(sqrt2(sqrt2(x))); 81 int b=(int)MeiLeh(sqrt2(x)); 82 int c=(int)MeiLeh(sqrt3(x)); 83 LL sum=getphi(x,a)+(LL)(b+a-2)*(b-a+1)/2; 84 for(int i=a+1;i<=b;i++) 85 { 86 LL w=x/p[i]; 87 sum-=MeiLeh(w); 88 if(i>c) continue; 89 LL lim=MeiLeh(sqrt2(w)); 90 for(int j=i;j<=lim;j++) 91 sum-=MeiLeh(w/p[j])-(j-1); 92 } 93 return sum; 94 } 95 int main() 96 { 97 init(); 98 while((scanf("%lld",&n))!=EOF) 99 printf("%lld\n",MeiLeh(n)); 100 return 0; 101 }