Help Hanzo (LightOJ - 1197) 【简单数论】【筛区间质数】
标签: 入门讲座题解 数论
题目描述
Amakusa, the evil spiritual leader has captured the beautiful princess Nakururu. The reason behind this is he had a little problem with Hanzo Hattori, the best ninja and the love of Nakururu. After hearing the news Hanzo got extremely angry. But he is clever and smart, so, he kept himself cool and made a plan to face Amakusa.
Before reaching Amakusa's castle, Hanzo has to pass some territories. The territories are numbered as a, a+1, a+2, a+3 ... b. But not all the territories are safe for Hanzo because there can be other fighters waiting for him. Actually he is not afraid of them, but as he is facing Amakusa, he has to save his stamina as much as possible.
He calculated that the territories which are primes are safe for him. Now given a and b he needs to know how many territories are safe for him. But he is busy with other plans, so he hired you to solve this small problem!
Input
Input starts with an integer T (≤ 200), denoting the number of test cases.
Each case contains a line containing two integers a and b (1 ≤ a ≤ b < 231, b - a ≤ 100000).
Output
For each case, print the case number and the number of safe territories.
Sample Input
3
2 36
3 73
3 11
Sample Output
Case 1: 11
Case 2: 20
Case 3: 4
Note
A number is said to be prime if it is divisible by exactly two different integers. So, first few primes are 2, 3, 5, 7, 11, 13, 17, ...
题意
给定(l, r),问区间([l, ;r])内有几个质数?
解析
因为(n)较大,且区间长度最大为(1e5),所以不能直接使用朴素(O(sqrt{n}))的方法来逐个判断区间的质数。
那么我们可以将埃氏筛的思想运用到区间上。用所有比(r)小的质数数来筛掉([l, ;r])区间中的合数。用欧拉筛提前处理出(sqrt{N})以内的质数。然后用这些质数去筛掉([l,;r])区间的合数。这样这个算法的时间复杂度就是(O(lenlog log{len}))了。
quiz为什么只需要筛出(sqrt{N})以内的素数?
埃氏筛中,一个质数(p)所能筛掉的第一个合数为(p imes p)((p imes 2, p imes 3, p imes 4, dots) 都在之前被其他的质数筛掉了。)如果(p)能筛掉的最小合数都比(N)大,那么这个(p)就是用不到的,就不用筛出这个(p)来。
通过代码
/*
Problem
LightOJ - 1997
Status
Accepted
Time
105ms
Memory
15856kB
Length
1168
Lang
C++
Submitted
2019-11-25 19:11:37
RemoteRunId
1640684
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e7 + 50;
typedef long long ll;
bool vis[MAXN], _vis[100005];
int prime[MAXN / 10], cnt = 0;
void get_prime() //欧拉线性筛.先筛出sqrt(n)范围内的质数.
{
vis[1] = 1;
for(int i = 2; i <= int(1e6 + 5); i ++){
if(!vis[i])
prime[++ cnt] = i;
for(int j = 1; j <= cnt && i * prime[j] <= int(1e6 + 5); j ++){
vis[i * prime[j]] = 1;
if(i % prime[j] == 0)
break;
}
}
return;
}
int main()
{
int times, _case = 0;
get_prime();
scanf("%d", ×);
while(times --){
ll a, b;
int ans = 0;
memset(_vis, 0, sizeof(_vis));
scanf("%lld%lld", &a, &b);
if(a == 1) _vis[0] = 1; //如果a是1. 1不是质数,但无法通过我们的方法筛掉1.所以先手动筛掉.
for(int i = 1; i <= cnt && 1ll * prime[i] * prime[i] <= b; i ++) //用小于sqrt(b)的素数,开始筛掉[1, b]区间的合数.
for(ll j = max(1ll * prime[i] * prime[i], a / prime[i] * prime[i]); j <= b; j += prime[i]){ //找到落在区间内的,能被prime[i]筛掉的第一个合数.
if(j >= a && j > prime[i]) //要让j落在区间中,且j是合数.
_vis[j - a] = 1;
}
for(int j = 0; j < b - a + 1; j ++)
if(!_vis[j])
ans ++;
printf("Case %d: %d
", ++ _case, ans);
}
return 0;
}