题目大意
给出一个区间 [ L , R ] [L,R] [L,R],问区间内的“小于3数”的个数是否小于 1 3 \frac{1}{3} 31。(实际上就是 1 1 1和所有素数)
解题思路
根据素数分布规律,素数越往后越分散。也可以自己推了一下,假设 x = 1 x=1 x=1,当 y = 48 y=48 y=48时,素数刚好占这个区间的三分之一,也就是按规律推广到一般情况,当 y − x + 1 > 48 y-x+1>48 y−x+1>48,自己尝试一下打印个数,肯定是小于 1 3 \frac{1}{3} 31,就肯定是 Y e s Yes Yes。如果不是,考虑到数据范围到 1 e 9 1e9 1e9,因此使用区间素数筛选即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=1e8; //maxn是b-a的最大值,即求素数的区间数量级
const int N=1e5;
bool is_prime[N]; //存[2,sqrt(b)]内的所有素数
bool is_prime_small[maxn]; //判断[a,b]范围内的每个数是不是素数
ll prime_num=0; //该区间素数的个数
//对区间[a,b)内的整数执行筛法,is_prime[i-a]=true --- 表示i是素数 注意这里下标偏移了a,所以从0开始。
void segment_sieve(ll a,ll b) {
for(ll i=2;i*i<=b;++i) is_prime_small[i]=true; //对[2,sqrt(b)]的初始化全为质数
for(ll i=0;i<=b-a;++i) is_prime[i]=true; //对下标偏移后的[a,b]进行初始化
for(ll i=2;i*i<=b;++i) {
if(is_prime_small[i]) {
for(ll j=2*i;j*j<=b;j+=i) is_prime_small[j]=false; //筛选[2,sqrt(b)];
//(a+i-1)/i得到最接近a的i的倍数,最低是i的2倍,然后筛选
for(ll j=max(2LL,(a+i-1)/i)*i;j<=b;j+=i) is_prime[j-a]=false;
}
}
for(ll i=a; i<=b; ++i)
if(is_prime[i-a])
if(i!=1)
prime_num++;
}
int main(){
int n,x,y;
cin>>n;
while(n--){
cin>>x>>y;
if((y-x+1)>48) cout<<"Yes"<<endl;
else{
prime_num=0;
segment_sieve(x,y);
if(x==1) prime_num++; ///注意这里一定要特判不然WA到哭
if(prime_num*3<y-x+1) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}