原题链接:点击打开链接
这道题乍一看非常简单,就是判断素数而已,但是实际上,由于题目限制的时间只有100ms,所以普通的方法很容易超时。
这里需要用到素数筛选法。
素数筛选法适用于求不大于给定数n的素数。
核心思想就是,首先假设从2到n所有的数都是素数,然后从2开始遍历,把所有2的倍数全部标记为非素数,接着找下一个没有被标记的(素)数,也就是3,同样把3的倍数全部标记为非素数。重复上述步骤,找到5,标记5的倍数,找到7,标记7的倍数。最后剩下的数就全部都是素数了。
贴一段素数筛选法的代码:
memset(prime,true,sizeof(prime));
prime[2]=true;
for(i=3;i*i<=100001;i+=2)
{
if(prime[i])
{
for(j=2*i;j<=100001;j+=i)
{
prime[j]=false;
}
}
}
这段代码已经经过一些小优化,由于除了2以外,其他的素数都是奇数,所以可以直接遍历所有奇数,这样效率就提高了一倍。
素数筛选法就这么简单,接下来额外介绍一个和本题无关的快速判断一个数是不是素数的算法。
根据孪生素数猜想,除了2和3以外,其他的素数全部分布在6的倍数周围,比如5(6)7,11(12)13,17(18)19。
所以可以下这样的结论,或者说猜想:除了2和3外,所有的素数都与6的倍数相邻,但是与6的倍数相邻的,不一定是素数。
有了这个猜想,我们就只需要判断每个6的倍数周围的数是不是素数就可以了。
上代码
int Prime(int n)
{
int i;
if(n==3 || n==5)
return 1;
if(n%6!=1 && n%6!=5)
return 0;
for(i=5;i<=sqrt(n);i+=6)
if(n%i==0 || n%(i+2)==0)
return 0;
return 1;
}
最后还有这道题的ac代码
#include<stdio.h>
#include<string.h>
bool prime[100001];
int num[10000];
int main()
{
int i,j,k,n,ans,flag;
int left,right,mid;
num[0]=2;
k=1;
memset(prime,true,sizeof(prime));
for(i=3;i*i<=100001;i+=2)
{
if(prime[i])
{
for(j=2*i;j<=100001;j+=i)
{
prime[j]=false;
}
}
}
for(i=3;i<=100001;i+=2)
{
if(prime[i])
num[k++]=i;
}
while(scanf("%d",&n)!=EOF)
{
flag=0;
ans=0;
left=0;right=k-1;
while(left<right)
{
if(n>num[right])
{
flag=right+1;
break;
}
mid=(left+right)/2;
if(num[mid]>n)
{
if(num[mid-1]<=n)
{
flag=mid;
break;
}
else
{
right=mid-1;
}
}
else if(num[mid]==n)
{
flag=mid+1;
break;
}
else if(num[mid]<n)
{
if(num[mid+1]>n)
{
flag=mid+1;
break;
}
else if(num[mid+1]==n)
{
flag=mid+2;
break;
}
else
{
left=mid+1;
}
}
}
printf("%d\n",flag);
}
return 0;
}
这道题除了需要用素数筛选法以外,还需要打表后用二分查找,要不然会超时。