题目描述
算法提高 找素数时间限制:1.0s 内存限制:256.0MB
问题描述
给定区间[L, R] , 请计算区间中素数的个数。
输入格式
两个数L和R。
输出格式
一行,区间中素数的个数。
样例输入
2 11
样例输出
5
数据规模和约定
2 < = L < = R < = 2147483647 R-L < = 1000000
从题上可以看出题目数据肯定很大,所以暴力跑肯定很慢,空间换时间的素数筛法也难处理这么大的数据,所以,感觉这个题考的是素数筛法的变形,先说一下什么是素数筛法。
素数筛法:例如求5000000以内的素数,先建立一个长度为5000100的数组,将数组内数字置为0,因为2,3,5是素数,所以将下标为0,1,3的数组的数字变成1,记录素数情况,然后我们知道,一个素数的2倍,3倍,4倍........一定不是一个素数,所以用一个循环判断当前的a[]下标所示的数字是否为素数,如果为素数,进入内层循环,将下标为当前素数下标的2倍,3倍...的数组a[]的标记变成1,这样,素数的倍数就被标记了,最后判断标记变量是否为0,如果为0,说明当前下标表示的数字为素数。
这道题也可以利用筛法的思想,先将一定范围内的素数打表存入一个新数组,然后用新数组内记录的素数对题目所给区间内的数字进行判断。
#include<stdio.h>
#include<string.h>
long long a[501000];
long long s[1000100];
int next[1000100];
int main()
{
int i,j,k,m,n;
memset(a,0,sizeof(a));
a[0]=1;//标记不为素数的数字
a[1]=1;
for(i=1;i<=500100;i++)//素数筛法
{
if(a[i]==0)
{
for(j=2;j*i<=500100;j++)
{
a[i*j]=1;//一个素数的倍数都不为素数,本身除外
}
}
}
j=1;
for(i=1;i<=500100;i++)
{
if(a[i]==0)
{
s[j++]=i;//用新数组记录打表打出来的数
}
}
int t=j-1;
while(scanf("%d%d",&m,&n)!=EOF)
{
memset(next,0,sizeof(next));
for(i=1;i<=t;i++)
{
if(s[i]<=n)//如果当前素数比区间大,不用计算
{
j=m/s[i];//从题上给的区间判断左边是当前素数的几倍
if(j<=1)//如果倍数小于1,就从2开始
j=2;
for(;j*s[i]<=n;j++)
{
// printf("s[i]===%d j===%d ==%d\n",s[i],j,j*s[i]);
if(j*s[i]>=m&&j*s[i]<=n)//判断素数的倍数是否在区间内
{
next[j*s[i]-m+1]=1;//因为数据太大,记录方式为区间内第几个数字
}
}
}
else
{
break;
}
}
int sum=0;
for(i=1;i<=n-m+1;i++)//判断区间内被标记的数字个数
{
if(next[i]==0)
sum++;
}
printf("%d\n",sum);
}
return 0;
}