P1835 素数密度_NOI导刊2011提高(04)
题目描述
给定区间L,R,请计算区间中素数的个数。
错误日志: 题目给出的数为 (MAX_INT) 很容易越界, 没有开 (longlong)
Solution
我们无法再规定时间内处理出 (1 - R) 的所有质数
考虑枚举质因数筛去区间内合数, 只需要处理出 (1 - sqrt{R}) 的质数即可
然后在 ([L, R]) 内, 一个质数 (p) 其倍数个数(即筛去合数个数)为 (lceil frac{L}{p}
ceil to lfloor frac{R}{p}
floor)
注意这里不能取 (1) 否则有可能将质数筛去((1 * p = p))
筛去, 最后枚举区间内没被筛过的数即为质数
记得用小技巧((base = L - 1))将数组范围控制在 ([1, R - L]) 之间
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#include<cmath>
#define LL long long
#define REP(i, x, y) for(LL i = (x);i <= (y);i++)
using namespace std;
LL RD(){
LL out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const LL maxn = 2000019;
LL L, R, base;
bool isprime[maxn], lastisprime[maxn];
LL prime[maxn];
LL nump;
void get_prime(LL n){
REP(i, 2, n){
if(!isprime[i])prime[++nump] = i;
for(LL j = 1;j <= nump && prime[j] * i <= n;j++){
isprime[prime[j] * i] = 1;
if(i % prime[j] == 0)break;
}
}
}
int main(){
L = RD(), R = RD();base = L - 1;
get_prime(sqrt(R));
REP(i, 1, nump){//枚举质数,筛去合数
LL p = prime[i];
LL l = L / p, r = R / p;
if(l * p < L)l++;//向上取整
if(l == 1)l++;
//prLLf("l=%d r=%d
", l, r);
REP(j, l, r){
lastisprime[j * p - base] = 1;
}
}
LL ans = 0;
REP(i, L, R){
if(!lastisprime[i - base])ans++;
}
printf("%lld
", ans);
return 0;
}