2019 ICPC 徐州区域赛 - C <3 numbers(素数密度)

9 篇文章 0 订阅

题目链接


题目大意

给出一个区间 [ 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 yx+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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值