P1865 A % B Problem (素数筛法,前缀和)

题目描述

区间质数个数

输入输出格式

输入格式:

 

一行两个整数 询问次数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;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章