prime sieve 素数筛

index > Algebra > prime sieve


主要内容

本篇只收录较快的线性筛法,作用就是求 2 到 n 的所有素数,顺便得到判断数组。

单纯求素数,标记所有合数。(常用)

const int MAXN = -1;//10000005
int prime[MAXN],pnum;
bool is_composite[MAXN];

void sieve(const int &n) {
  	// 1 is exception
    //clock_t begin = clock();
    for (int i = 2; i < n; ++i) {
        if (!is_composite[i]) prime[++pnum]=i;
        for (int j = 1; j <=pnum  && i * prime[j] < n; ++j) {
            is_composite[i * prime[j]] = true;
            if (i % prime[j] == 0) break;
        }
    }
    //cout << (double) (clock() - begin) / CLOCKS_PER_SEC << endl;
}

求素数的同时,求所有合数最小的质因子。

const int MAXN = -1;//10000005
int prime[MAXN], pnum;
int min_composite[MAXN];

void sieve(const int &n) {
  	// 1 is exception
    //clock_t begin = clock();
    for (int i = 2; i < n; ++i) {
        if (!min_composite[i]) {

            prime[++pnum] = i;
            min_composite[i] = i;
        }
        for (int j = 1; j <= pnum && prime[j] <= min_composite[i] && i * prime[j] < n; ++j) {
            min_composite[i * prime[j]] = prime[j];
//            if (i % prime[j] == 0) break;
        }
    }
    //cout << (double) (clock() - begin) / CLOCKS_PER_SEC << endl;
}

&& prime[j] <= min_composite[i]if (i % prime[j] == 0) break;相差无几,任选其一即可。

理解

Sieve of Eratosthenes 的思路很好理解,每次装入一个素数就把所有这个数的倍数都划掉。但是容易发现,很多数会被多次划掉。时间复杂度是 O ( n l o g l o g n ) O(n log log n ) O(nloglogn)的,不太理想。

Euler’s sieve 的角度其实不太一样(尽管两者代码很相似)。为了理解,最好优先看第二份代码。下面是我的个人理解。

既然不希望合数被重复删去,那么应该尽量让所有合数是被最小素因子去掉的。这就构成了一种转移。假设 p i pi pi i i i的最小素因子,那么对于所有小于等于 p i pi pi的素数 p j pj pj有, p j ∗ i pj*i pji是一个合数,并且以 p j pj pj为最小素因子。

当枚举到 i i i的时候,已经有了不超过 i i i的所有最小素数,那就可以通过遍历 i ∗ p r i m e [ j ] i * prime_{[j]} iprime[j] 依此把后面的数给删去。

被删去的状态,是从最小素数集合 p r i m e [ j ] prime_{[j]} prime[j]中转移过来的,所以是可以理解新的合数是被最小的素因子删去了。

但不能一直删,当 i % p r i m e [ j ] = = 0 i \% prime[j] == 0 i%prime[j]==0 成立,说明此时的 p r i m e [ j ] prime[j] prime[j]恰好是 i i i的最小素数,KaTeX parse error: Undefined control sequence: \* at position 3: i \̲*̲ prime\_{[j+1]}之后的倍数,应该由 i i i作为最小素因子时删去。

p r i m e [ j ] < = m i n c o m p o s i t e [ i ] prime[j] <= min_composite[i] prime[j]<=mincomposite[i]也是类似的判断。

虽然不知道如何验证,但是实事便是,所有的数都可以被常数次遍历。一般情况我们不需要最小素因子,所以可以优化成布尔型经行遍历。

花边

这个算法最早的渊源是和欧拉有关的,但好像不是欧拉自己提出的。

Euler’s proof of the zeta product formula contains a version of the sieve of Eratosthenes in which each composite number is eliminated exactly once.[8] The same sieve was rediscovered and observed to take linear time by Gries & Misra (1978).[19] It, too, starts with a list of numbers from 2 to n in order.

后人观测到了这个算法就发了一篇 CACM 期刊论文,而巨人欧拉只是以这个方法用来辅助一下更重要的证明(黎曼),没当回事儿···ORZ

但线性筛的概念,可以拓展到类积性函数的求法。去理解这个算法有更长远的意义。

参考

Math note — linear sieve By Nisiyama_Suzune 这篇博客有讲到线性筛

Sieve of Eratosthenes

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值