题目描述
算法提高 找素数时间限制: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;
}