zoukankan      html  css  js  c++  java
  • 埃氏筛法的一般写法(区间筛法)

    问题

    求 $[L, R]$ 之间的素数表。

    解法

    一个合数 $n$ 的最小素因子不超过 $sqrt{n}$。因此,在埃氏筛法的过程中,每当“新发现”一个素数 $p$,可以从 $p^2$ 筛起,而不必从 $2p$ 筛起。

    先用埃氏筛法求出 $[1,lfloor sqrt{R} floor]$ 上的素数表,再在 $[L, R]$ 上用埃氏筛法求素数。

    const int N(1e5);
    bool isprime[N];
    int prime[N];
    void init() {
        memset(isprime, -1, sizeof isprime);
        isprime[0] = isprime[1] = 0;
        int np = 0;
        for (int i = 0; i < N; i++) {
            if (isprime[i]) {
                prime[np++] = i;
                for (int j = i * i; j < N; j += i)
                    isprime[j] = 0;
            }
        }
    }
    typedef long long ll;
    const int M(1e5);
    bool ok[M];
    int res[M];
    int seive(ll l, ll r) {
        assert(1 <= l && l <= r);
        memset(ok, -1, sizeof ok);
        if (l == 1) ok[0] = 0;    //error-prone
        int k = sqrt(r);
        for (int i = 0; prime[i] <= k; i++) {
            ll j = (l + prime[i] - 1) / prime[i] * prime[i];
            j = max(j, (ll) prime[i] * prime[i]);
            for (; j <= r; j += prime[i])
                ok[j - l] = 0;
        }
        int np = 0;
        for (int i = 0; i <= r - l; i++)
            if (ok[i]) res[np++] = i + (ll) l;
        return np;
    }

     更新:

    不必先把 $[2, lfloor sqrt{R} floor]$ 上的素数存下来。更好的做法是先分别做好 $[2, lfloor sqrt{R} floor]$ 和 $[L, R]$ 的表,然后从 $[2, lfloor sqrt{R} floor]$ 的表中筛得素数的同时,也将其倍数从 $[L, R]$ 中划去。

    const int N = 1e6 + 5, M = sqrt(1e9);
    
    bool is_prime[N];
    // 注意:用 sqrt(1e9) + 1 作为数组大小不符合标准, sqrt(1e9) 不是编译期常量,但是 gcc 支持这样做。
    bool is_prime_small[M + 1];
    
    void segment_seive(int l, int r) { // [l, r]
        assert(1 <= l && l <= r);
        int t = sqrt(r + 0.5);
        for (int i = 2; i <= t; i++)
            is_prime_small[i] = true;
        for (int i = 0; i <= r - l; i++)
            is_prime[i] = true;
        if (l == 1) is_prime[0] = false;
    
        for (int i = 2; i <= t; i++)
            if (is_prime_small[i]) {
                for (int j = i * i; j <= t; j += i)
                    is_prime_small[j] = false;
                for (int j = max(i * i, (l + i - 1) / i * i); j <= r; j += i)
                    is_prime[j - l] = false;
            }
    }

     

  • 相关阅读:
    Android 走向MD的配色风格
    Android热点回顾第六期
    C#集合类:动态数组、队列、栈、哈希表、字典(转)
    Google Chrome默认字体设置(Win)
    C# Socket的粘包处理(转)
    设计模式原则总结--读《大话设计模式》有感 <转>
    C#设计模式学习笔记-单例模式(转)
    C# 编写Windows Service(windows服务程序)
    C# 获取农历日期
    C# 中怎么将string转换成int型
  • 原文地址:https://www.cnblogs.com/Patt/p/4805212.html
Copyright © 2011-2022 走看看