题目描述
区间质数个数
输入输出格式
输入格式:
一行两个整数 询问次数n,范围m
接下来n行,每行两个整数 l,r 表示区间
输出格式:
对于每次询问输出个数 t,如l或r∉[1,m]输出 Crossing the line
输入输出样例
输入样例#1: 复制
2 5 1 3 2 6输出样例#1: 复制
2 Crossing the line说明
【数据范围和约定】
对于20%的数据 1<=n<=10 1<=m<=10
对于100%的数据 1<=n<=1000 1<=m<=1000000 -10^9<=l<=r<=10^9 1<=t<=1000000
第一眼肯定会想到素数筛法,但还需将此算法进行改进。
如果每一次记录当前这个数之前有几个是素数,则再求某一区间内的素数个数就变得极为容易。(注意:在求区间[L, R]内的素数个数时,不能直接用num[R] - num[L],显然这样减少一个计算了一个数。
例如:计算区间[2, 8]内的素数个数,
数字:1 2 3 4 5 6 7 8 9 10
前缀和:0 1 2 2 3 3 4 4 4 4
num[8] - num[2] = 4 - 1 = 3,显然是错的,所以应该减去他的前一个数的前缀和,即num[R] - num[L-1])
素数筛法模板(加计数素数前缀和)
void init(){
memset(notprime, false, sizeof(notprime));
memset(num, 0, sizeof(num));
notprime[0] = notprime[1] = true;
num[0] = 0; num[1] = 0;
for(int i = 2; i < maxn; i++){
if(!notprime[i]){
num[i] = num[i-1] + 1;
if(i > maxn/i) continue;
for(int j = i*i; j < maxn; j += i)
notprime[j] = true;
}
else num[i] = num[i-1];
}
}
ac代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
typedef long long LL;
const int maxn = 1e6+5;
bool notprime[maxn];
int num[maxn];
int n, m;
int l, r;
void init(){
memset(notprime, false, sizeof(notprime));
memset(num, 0, sizeof(num));
notprime[0] = notprime[1] = true;
num[0] = 0; num[1] = 0;
for(int i = 2; i < maxn; i++){
if(!notprime[i]){
num[i] = num[i-1] + 1;
if(i > maxn/i) continue;
for(int j = i*i; j < maxn; j += i)
notprime[j] = true;
}
else num[i] = num[i-1];
}
}
int main()
{
init();
scanf("%d%d", &n, &m);
while(n--){
scanf("%d%d", &l, &r);
if(l < 1||r > m) printf("Crossing the line\n");
else printf("%d\n", num[r] - num[l-1]);
}
return 0;
}