美文网首页
区间素数线性筛选

区间素数线性筛选

作者: 你今天作业做了吗 | 来源:发表于2019-04-24 12:10 被阅读0次

区间素数线性筛选

假设应用场景为求一个区间长度远小于右端点的所有素数,该区间为 [l, r] 。如若使用朴素素数线性筛选,则需要的时间复杂度为 T(r)=rln(lnr) , 如果使用区间素数线性筛选算法,则需要的时间复杂度为 T(r)=\sqrt{r} ln(ln \sqrt{r}) .

思想

首先使用朴素素数线性筛选算法获得 [1, \sqrt{r}] 的素数集合 \Omega , 然后利用该集合的素数 p_ik 倍筛掉区间 [l, r] 的合数,其中
k = max(2, \lceil\frac{l}{p_i}\rceil)

时间复杂度

设筛选区间为 [l, r] 的所有素数。则由算法的特性可知,对于每个素数 p_i ,均要筛掉 \lfloor\frac{r-l}{p_i}\rfloor 个合数, 若区间的长度远小于区间右端点,则算法的时间复杂度花费主要在 [1, \sqrt{r}] 的素数筛选上。

则总的时间复杂度为

T(r) = \sum_{p_i=2}^{\sqrt{r}}{\frac{r-l}{p_i}}=\sqrt{r}ln(ln\sqrt{r}),p_i\ is\ prime.

即在该应用场景下,可以以 \sqrt{n} 的复杂度获得该区间内的所有素数

代码部分:

using array_int = vector<int>;
using array_int_ref = array_int &;
using array_bool = vector<bool>;
using array_bool_ref = array_bool &;

/***
朴素素数线性筛选算法
**/
void regular_sieve(array_int_ref array, const int size) {
    // 使用sqrt(size)大小的素数来进行筛选,进行优化
    const int sqrt_size = sqrt(size) + 1;

    // 使用标记数组进行标记是否为素数
    array_bool is_prime(size + 1, true);
    for (int i = 2; i <= sqrt_size; ++i) {
        if (is_prime[i]) {

            // 使用i*i,进行优化
            for (int j = i * i; j <= size; j += i) {
                is_prime[j] = false;
            }
        }
    }

    // 清空无效数据
    array.clear();

    // 将标记为素数的数收集起来
    for (int i = 2; i <= size; ++i) {
        if (is_prime[i]) {
            array.push_back(i);
        }
    }
}

/***
区间素数筛选算法
**/
void segment_sieve(array_int_ref array, const int l, const int r) {
    // 清空无效数据
    array.clear();

    // 判断输入范围是否有效
    if (l > r) {
        return;
    }

    // 先使用朴素的线性素数筛选算法,获得[1, sqr(n)+1]内的所有素数
    const int sqrt_size = sqrt(r) + 1;
    const int total = r - l + 1;
    array_int sqrt_array;
    regular_sieve(sqrt_array, sqrt_size);

    // 利用朴素线性素数筛选算法所获得的素数集合,筛选[l, r]内的素数集合
    array_bool is_prime(total + 1, true);
    for (int i = 0; i < sqrt_array.size(); ++i) {
        const auto& p = sqrt_array[i];

        // 获取在区间[l, r]内最小k_min倍p的合数c_min,k_min最小为2,
        int k_min = max(2, (l / p) + (l % p == 0 ? 0 : 1));
        int c_min = k_min * p;

        // 将区间[l, r]映射到[0, total-1],筛掉区间内的合数
        for (int j = c_min - l; j < total; j += p) {
            is_prime[j] = false;
        }
    }

    // 将区间[0, total-1]所标记的素数映射到[l, r]内,并将素数添加到array数组
    for (int i = 0; i < total; ++i) {
        if (is_prime[i]) {
            array.push_back(i + l);
        }
    }
}

相关文章

  • 区间素数线性筛选

    区间素数线性筛选 假设应用场景为求一个区间长度远小于右端点的所有素数,该区间为 。如若使用朴素素数线性筛选,则需...

  • 素数线性筛选

    素数线性筛选 素数的定义是除了1和自身能被整除外,没有其他数能被它整除。除此之外,1既不是素数,也不是合数。因此,...

  • 线性筛选法求素数

  • Algorithm

    素数筛选

  • 素数筛选

    今天在面试时被问到了一个问题:求不大于n的最大素数,当时只想出暴力解法,回来查资料找到了正确的求解方法。 素数筛法...

  • 筛选素数/筛选质数

  • 2019-03-21 [蓝桥杯][算法提高VIP]找素数

    题目描述给定区间[L, R] , 请计算区间中素数的个数。 数据规模和约定2 < = L < = R...

  • 线性筛素数

    对于每一个数: 1.若为素数,由于自身只能被1和自己整除,所以在筛素数时不会被筛去。 2.若为合数,由于一定能被素...

  • 【python吉比特】求素数?

    题目:输入M、N,1 < M < N < 1000000,求区间[M,N]内的所有素数的个数。素数定义:除了1以外...

  • 素数算法

    寻找素数的算法有很多,最著名应是筛选法,以下是笔者用JavaScript编写的一个找素数的函数,借鉴了各种找素数的...

网友评论

      本文标题:区间素数线性筛选

      本文链接:https://www.haomeiwen.com/subject/ylowgqtx.html