很早之前写过 $\pi(x)$ 的计算 ,在知乎上用它回答问题的时候,发现我怎么没有写 求第 $n$ 个素数。
做法依赖于 $\pi(x)$ 的计算,$\pi(x)$ 表示不超过 $x$ 的素数个数
素数定理( 这里就不证了)
从而我们知道:
其中,$p_n$ 为第 $n$ 个素数,显然 $p_n$ 是 $\pi(x) = n$ 最小的解。
$p_n$ 求解
- 预处理小于 $N$ 的素数
- 初始值 $n\ln n$
- 牛顿梯度法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| #include<bits/stdc++.h> using namespace std; typedef long long LL; const int N = 1e8+2; int p[N],pi[N]; bool isp[N]; int initprime(){ int cnt=1;p[1]=2;isp[2] = true; for(int i=3;i<N;i+=2) isp[i]=true; for(int i=3;i<N;i+=2){ if(isp[i]) p[++cnt] = i; for(int j = 2,t=(N-1)/i + 1;j <= cnt && p[j] < t; ++j){ isp[i * p[j]] = false; if(i%p[j] == 0) break; } } return cnt; } const int M = 8; const int PM = 2*3*5*7*11*13*17*19; int phi[PM+1][M+1],sz[M+1]; void init(){ initprime(); pi[2] = 1; for(int i=3;i<N;++i){ pi[i]=pi[i-1]; if(isp[i]) ++pi[i]; } sz[0]=1; for(int i=0;i<=PM;++i) phi[i][0]=i; for(int i=1;i<=M;++i){ sz[i]=p[i]*sz[i-1]; for(int j=1;j<=PM;++j){ phi[j][i]=phi[j][i-1]-phi[j/p[i]][i-1]; } } } LL primepi(LL x); LL primephi(LL x, int s){ if(s <= M) return phi[x%sz[s]][s]+(x/sz[s])*phi[sz[s]][s]; if(x/p[s] <= p[s]) return primepi(x)-s+1; if(x/p[s]/p[s] <= p[s] && x<N){ int s2x = pi[(int)(sqrt(x+0.2))]; LL ans = pi[x]-(s2x+s-2)*(s2x-s+1)/2; for(int i=s+1;i<=s2x;++i){ ans+=pi[x/p[i]]; } return ans; } return primephi(x,s-1)-primephi(x/p[s],s-1); } LL primepi(LL x){ if(x<N) return pi[x]; int ps2x = primepi(int(sqrt(x+0.2))); int ps3x = primepi(int(cbrt(x+0.2))); LL ans = primephi(x,ps3x) + LL(ps2x+ps3x-2)*(ps2x-ps3x+1)/2; for(int i =ps3x+1,ed = ps2x;i<=ed;++i){ ans -= primepi(x/p[i]); } return ans; } bool isprime(LL n){ if(n<N) return isp[n]; for(int i=1;p[i]<=n/p[i]&&i<N;++i){ if(p[i]&&n%p[i]==0) return false; } return true; } LL primep(LL n){ if(n <= pi[N-1]) return p[n]; LL ans= n*log(n), err = log(n)/log(10); LL m = primepi(ans); while(m<n||m>n+err){ ans += (n-m)/(log(m)-1)*log(m)*log(m); m = primepi(ans); } int step = m-n; for(int i=0;i<=step;++i){ while(!isprime(ans)) --ans; --ans; } return ++ans; }
int main(){ init(); LL n; while(cin>>n){ cout<<primep(n)<<endl; } return 0; }
|
第 $n$ 个素数和 $\pi(x)$ 的网站
世界纪录保持者的求法