題目描述
區間質數個數
輸入輸出格式
輸入格式:
一行兩個整數 詢問次數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;
}