题目链接:Help Hanzo - LightOJ 1197 - Virtual Judge (vjudge.net)
题意
多组数据,每组输入两个数a,b,求区间a,b内的素数个数。
其中.
思路
首先我们看到数据范围就能知道,传统的质数筛肯定行不通了
(令)
那么有个经典的方法就是筛出内的质数,用内的质数把内的所有合数筛掉
也就是说我们只需用欧拉筛筛出区间内的质数即可
那么对于区间内的素数,自然是用内的质数把内的所有合数筛掉.
在筛合数的时候我们可以对左区间进行一定的优化处理:
用质数来筛合数时的左区间选择可以是第一个能被质数筛掉的质数即(到用筛时都会在之前被其他质数筛掉),另外要保证的一点时筛的左区间要,所以可以是,那么左区间的选择就是.
这就是利用了埃氏筛的思想来处理区间
还有一个值得注意的点,可能非常大,所以在处理的时候我们可以把区间映射到
Solution
Status | Accepted |
---|---|
Time | 62ms |
Memory | 888kB |
Length | 906 |
Lang | C++ 17 (g++ 7.5.0) |
#include <bits/stdc++.h>
using namespace std;
const int N = (1 << 16) + 10;
bool vis[N], vis1[100010];
int p[N], cnt;
void get_primes(){
for (int i = 2; i < N; i++) {
if (!vis[i]) p[cnt++] = i;
for (int j = 0; p[j] < N / i; j++){
vis[i * p[j]] = true;
if (i % p[j] == 0) break;
}
}
}
int segment_sieve(long long a, long long b){
memset(vis1, 0, sizeof vis1);
if(a == 1) a++;
int ans = 0;
for(int i = 0; p[i] <= b / p[i]; i++){
long long st = max(1LL * p[i] * p[i], a / p[i] * p[i]);
for(long long j = st; j <= b; j += p[i]){
vis1[j - a] = 1;
}
}
for(int i = 0; i <= b - a; i++)
if(!vis1[i])
ans++;
return ans;
}
signed main(){
get_primes();
int t;
scanf("%d", &t);
for(int k = 1; k <= t; k++){
long long a, b;
scanf("%lld%lld", &a, &b);
printf("Case %d: %d\n", k, segment_sieve(a, b));
}
return 0;
}