转发出处:http://blog.csdn.net/doyouseeman/article/details/54747260
Description
第1个质数是2,第3个质数是5,给出一个数N,求第N个质数。
Solution
很明显这个要二分答案。
现在的主要问题就是求f[i]表示i里面有多少个质数。
这里可以用个非正式的洲阁筛。
设
f[i]表示i以内有多少个质数
p[i]表示第i个质数
g[i][j]表示前i个数不被p[1...j]整除的数有多少个
那么先来看看f,首先我们知道一个数i可以被
i√
以内的质数给筛掉,那么筛不掉的就是质数,所以有
f[i]=f[i√]+g[i][f[i√]]
-1,因为1不是质数。
然后p可以用线筛来解决。
g[i][j]可以从g[i][j-1]推过来,但是g[i][j-1]还包括一些是p[j]的倍数的数:
p[j],2p[j],3p[j],4p[j]...ip[j]p[j]
,所以就要排除掉
[1...ip[j]]中是p[1...j−1]倍数的
,所以有
g[i][j]=g[i][j−1]−g[ip[j]][j−1]
但是只有这个还不行,时间卡不过去。
我们考虑如何在根号时间内处理好。
那么很明显要优化求g的时间。
所以这里有两个优化:
1、当
f[i]<=j
,那么g[i][j]=1,因为j包含了组成[2…i]的所有质数,那么除了1以外,其他的数都会被整数。
2、如果不满足上面的条件,当
f[i√]<=j
,那么g[i][j]=f[i]+1-j,因为[1…i]的数可以由
i√
里所有的质数给筛掉,但是j包含了这些质数,那么只有除了这j个质数之外的质数,和1可以不被整除了。
剩下的要考虑的就是空间与时间的问题,51Nod这道题不打表还跑得挺慢的。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
const int maxn=7500000+7;
typedef long long ll;
using namespace std;
ll i,j,k,t,n,m,ans;
ll r,mid,l;
int f[maxn],p[maxn];
bool bz[maxn];
ll g(ll n,int m){
if(!m)return n;
if(m==1)return n-n/2;
if(n<=maxn-7){
if(f[n]<=m)return 1;
if(f[(int)sqrt(n)]<=m)return f[n]-m+1;
}
return g(n,m-1)-g(n/p[m],m-1);
}
bool pan(ll x){
ll y=sqrt(x);
return f[y]+g(x,f[y])-1>=n;
}
int main(){
fo(i,2,maxn-7){
if(!bz[i])p[++p[0]]=i;
fo(j,1,p[0]){
t=p[j]*i;
if(t>maxn-7)break;
bz[t]=1;if(i%p[j]==0)break;
}
}
fo(i,2,maxn-7)f[i]=f[i-1]+(bz[i]==0);
scanf("%d",&n);
l=1,r=22801763489;
while(l<r){
mid=(l+r)/2;
if(pan(mid))r=mid;else l=mid+1;
}
printf("%lld\n",l);
}