筛素数

筛素数

主要就是埃氏筛,欧拉筛(线性筛)。

1. 埃氏筛

思路:

首先知道 \(2\) 是质数,然后划掉所有 \(2\) 的倍数,找到第一个没划掉的,它也是素数,再将它的倍数划掉,以此类推。

图片来源于网络

比较好理解。

有个小优化,考虑筛 \(x\) 的倍数时 \(x^2\) 以前都被筛过了,所以可以直接从 \(x^2\) 开始枚举,复杂度 \(O(n\log\log n)\)

CODE
for(int i=2;i<=R;i++){
    if(!ntp[i]){
        pri[++ttp_]=i;
        for(int j=i;j<=R/i;j++) ntp[i*j]=1; //不要用 j=i*i ,会越界
    }
}

欧拉筛(线性筛)

其实它可以筛所有的积性函数,我不会就是了

我们发现埃氏筛优化后还有重复筛的,考虑能不能一个数只被筛一次。

我们让一个数只被它的最小质因子筛掉,只要改变一下它筛的实现。

具体的,对于一个数(无论质数和合数)都对 \(1\) 到其最小质因数内所有质数进行扩展(也就是筛掉它们的积)。

CODE
for(int i=2;i<=n;i++){
    if(!ntp[i]) pri[++ttp_]=i;
    for(int j=1;j<=ttp_;j++){
        if(i*pri[j]>=R) break;
        ntp[i*pri[j]]=1;
        if(!(i%pri[j])) break; // 只扩展到最小质因数
    }
}

为什么要扩展到其最小质因数:

设现在这个数 \(i=pt\),其中 \(p\) 是其最小质因数。

当我们筛 \(x*pt\)\(x\) 是目前的质数 \(pri_j\)),若 \(x>p\),则这个数可以被 \(p\)\(xt\) 筛掉,就会造成重筛,所以到此为止。

为什么不会漏筛:

因为一个和数一定可以分成 \(x*pt\),其中 \(x<p\) 且为质数,\(t\) 为合数或 \(1\) ,所以这个合数一定会在筛 \(pt\) 时被筛掉。

posted @ 2023-08-04 17:05  xrlong  阅读(7)  评论(0编辑  收藏  举报