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;
} 

 

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