常州模拟赛d2t1 小X的质数

题目背景

小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的

情感。小 X 认为,质数是一切自然数起源的地方。

题目描述

在小 X 的认知里,质数是除了本身和 1 以外,没有其他因数的数字。

但由于小 X 对质数的热爱超乎寻常,所以小 X 同样喜欢那些虽然不是质数,

但却是由两个质数相乘得来的数。

于是,我们定义,一个数是小 X 喜欢的数,当且仅当其是一个质数,或是两

个质数的乘积。

而现在,小 X 想要知道,在 L 到 R 之间,有多少数是他喜欢的数呢?

输入输出格式

输入格式:

从文件 prime.in 中读取数据。

第一行输入一个正整数 Q,表示询问的组数。

接下来 Q 行,包含两个正整数 L 和 R,保证 L≤R。

输出格式:

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

输入输出样例

输入样例#1:
   1
1 6
输出样例#1:
5
【样例 1 解释】
6 以内的质数有 2、3、5,而 4 = 2 * 2,6 = 2 * 3,因此,2,3,4,5,6 都是小 X 喜欢的数,而 1 不是.
L,R <= 10^7 Q <= 10^5
分析:这道题会线性筛就可以解决了.因为线性筛就是筛出素数并且剔除掉素数与另一个数i的乘积的,对于两个素数的乘积,我们只需要判断一下i是不是素数就好了
不过因为询问较多,所以要用前缀和处理.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
int q, l, r;
long long flag[10000005], prime[10000005], tot = 0, ans, vis[10000005], vis2[10000005], maxn;
long long sum[10000005];
struct node
{
    int l, r;
}e[100005];

void init(int r)
{
    for (int i = 2; i <= r; i++)
    {
        if (!flag[i])
        {
            prime[++tot] = i;
            vis[i] = 1;
        }
        for (int j = 1; j <= tot; j++)
        {
            int t = i * prime[j];
            if (t > r)
                break;
            flag[t] = 1;
            if (vis[i])
                vis2[t] = 1;
            if (i % prime[j] == 0)
                break;
        }
    }
}

int main()
{
    scanf("%d", &q);
    for (int i = 1; i <= q; i++)
    {
        scanf("%d%d", &e[i].l, &e[i].r);
        if (e[i].r > maxn)
            maxn = e[i].r;
    }
    init(maxn);
    for (int i = 2; i <= maxn; i++)
    {
        if (vis[i])
            sum[i] = sum[i - 1] + vis[i];
        else
            sum[i] = sum[i - 1] + vis2[i];
    }
    for (int i = 1; i <= q; i++)
        printf("%lld
", sum[e[i].r] - sum[e[i].l - 1]);

    return 0;
}
 
原文地址:https://www.cnblogs.com/zbtrs/p/7417387.html