【NC235228】素数的个数

题目

素数的个数

欧拉筛

思路

数据范围这么大,显然不可能一个一个地判断素数

这里就要使用到之前说过的常用的并且效率还不错的筛选素数的方法–欧拉筛了

欧拉筛是什么?有什么用?

欧拉筛是一种高效的筛选素数的算法,它可以在线性时间复杂度内计算出小于等于 n n n 的所有素数。欧拉筛的时间复杂度为 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)
欧拉筛的基本思想是从小到大枚举每个数,如果它是素数,则将它的倍数标记为合数。在这个过程中,每个合数只会被它的最小质因子筛掉一次,因此时间复杂度是线性的。
欧拉筛的优点在于它具有良好的时间复杂度和空间复杂度,适合处理大规模的素数筛选问题。

先使用欧拉筛计算出一部分素数,然后根据这部分素数来判断给定的数是不是素数

由于题目所给的数据范围太大,设范围最大值为 m a x max max,所以不可能用欧拉筛选出在范围内的所有素数。考虑到结合素数判断,这里可以只筛出 m a x \sqrt{max} max 范围内的素数,这个范围大大缩小了,甚至可以用一般线性筛完成(这里为了效率,还是选择欧拉筛)

可以知道, ⌊ 2147483647 ⌋ = 46340 \lfloor \sqrt{2147483647} \rfloor=46340 2147483647 =46340,所以我们只需要筛出所有小于等于 46340 46340 46340 的素数即可。

那么就算筛出了这些素数,接下来需要做什么呢?

接下来就是从 L L L 枚举到 R R R,判断每一个数是不是素数,如果是则答案加一

怎么判断素数呢?

常规判断素数,我们通常采用时间复杂度为 n \sqrt n n 的算法。但是现在既然有了前面筛出来的素数,我们就可以直接遍历那些素数,并且限制遍历到的最大的素数不超过 n \sqrt n n ,这个比朴素的判断素数的算法优化了一些

代码

#include <stdio.h>

#define N 46340
#define M 2147483647

int primes[N + 1];    // 存储素数
int is_prime[N + 1];  // 判断是否是素数,初始为0表示全部是素数
int n;                // 素数的个数

/**
 * @brief 欧拉筛模板,筛出小于等于给定数的所有素数
 *
 * @param m 给定数
 */
void euler_sieve(int m) {
    int i = 0, j = 0;
    is_prime[0] = is_prime[1] = 1;
    for (i = 2; i <= m; i++) {
        if (!is_prime[i]) {
            // 如果是素数
            primes[n++] = i;
        }
        for (j = 0; j < n && i * primes[j] <= m; j++) {
            is_prime[i * primes[j]] = 1;  // 素数的倍数不是素数
            if (i % primes[j] == 0) break;
        }
    }
}

/**
 * @brief 判断给定的数是不是素数
 *
 * @param x 待判断的数
 * @return int 1表示是素数,0表示不是素数
 */
int check(int x) {
    if (x <= N) return !is_prime[x];
    for (int i = 0; i < n && primes[i] * primes[i] <= x; i++) {
        if (x % primes[i] == 0) return 0;
    }
    return 1;
}

int main(void) {
    euler_sieve(N);
    int l = 0, r = 0, ans = 0;
    scanf("%d%d", &l, &r);
    for (; l <= r; l++) {
        ans += check(l);
    }
    printf("%d\n", ans);
    return 0;
}
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木又可可

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值