JZOJ5458. 【NOIP2017提高A组冲刺11.7】质数

本文探讨了如何找出一个区间内既是质数或是两个质数乘积的数的数量。通过线性筛选法快速找到质数,并利用算法确保计算效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

小X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感。小X 认为,质数是一切自然数起源的地方。
在小X 的认知里,质数是除了本身和1 以外,没有其他因数的数字。
但由于小X 对质数的热爱超乎寻常,所以小X 同样喜欢那些虽然不是质数,但却是由两个质数相乘得来的数。
于是,我们定义,一个数是小X 喜欢的数,当且仅当其是一个质数,或是两个质数的乘积。
而现在,小X 想要知道,在L 到R 之间,有多少数是他喜欢的数呢?

Input

第一行输入一个正整数Q,表示询问的组数。
接下来Q 行。包含两个正整数L 和R。保证L≤R。

Output

输出Q 行,每行一个整数,表示小X 喜欢的数的个数。

Sample Input

输入1:
1
1 6

输入2:
10
282 491
31 178
645 856
227 367
267 487
474 697
219 468
582 792
315 612
249 307

输入3:
10
20513 96703
15236 86198
23185 78205
40687 48854
42390 95450
63915 76000
36793 92543
35347 53901
44188 76922
82177 90900

Sample Output

输出1:
5
样例1解释:
6以内的质数有2,3,5,而4=2*2,6=2*3。因此2,3,4,5,6都是小X 喜欢的数,而1 不是。

输出2:
97
78
92
65
102
98
114
90
133
29

输出3:
24413
23001
17784
2669
16785
3833
17712
6028
10442
2734

数据范围

这里写图片描述

题解

求质数是很简单的,
用线筛就可以做到O(n)了。

现在就考虑质数之间两两相乘的数,
很显然,这个数除了它本身,1,和这两个质数以外没有其他因数了,
所以就不用担心会出现重复的,就直接乘起来就好了。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10000003
#define P putchar
using namespace std;
void read(int &n)
{
    int t=0,p=1;char ch;
    for(ch=getchar();!('0'<=ch && ch<='9');ch=getchar())
      if(ch=='-') p=-1;
    for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
    n=t*p;
}

void write(int x)
{
    if(x>9)write(x/10);
    P(x%10+48);
}

int T,l,r,ss[N],tot,s[N];
bool bz[N],p[N];

int main()
{
    freopen("prime.in","r",stdin);
    freopen("prime.out","w",stdout);
    memset(bz,1,sizeof(bz));
    bz[1]=0;
    for(int i=2;i<=N-3;i++)
    {
        if(bz[i])ss[++tot]=i;
        for(int j=1;j<=tot && i*ss[j]<N;j++)
        {
            bz[i*ss[j]]=0;
            if(i%ss[j]==0)break;
        }
    }

    memset(p,1,sizeof(p));
    p[1]=0;
    for(int i=2;i<=N-3;i++)
    {
        s[i]=s[i-1];
        if(p[i])s[i]++;
        for(int j=1;j<=tot && i*ss[j]<N;j++)
        {
            if(!bz[i])p[i*ss[j]]=0;
            if(i%ss[j]==0)break;
        }
    }

    read(T);
    while(T--)
    {
        read(l);read(r);
        write(s[r]-s[l-1]);
        P('\n');
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值