线性筛质数

埃筛

for(int i=2; i<=n; i++)
{
    if(!del[i])
    {
        prim[++tot]=i;
        for(int j=i; i*j<=n; j++) del[i*j]=1;
    }
}

时间复杂度 \(O(n \log \log n)\)

欧筛

for(int i=2; i<=n; i++)
{
    if(!del[i]) prim[++tot]=i;
    for(int j=1; j<=tot&&prim[j]*i<=n; j++)
    {
        del[i*prim[j]]=1;
        if(i%prim[j]==0) break;
    }
}

if(i%prim[j]) break; 是最关键的一句话

是用来防止重复的,作用如下:

如果 \(prime_x\)\(y\) 的最小质因数,那就说 \(y\) 是符合关于 \(prime_x\) 的“筛条件”的

\(j\) 循环到 \(i \mod prime_j\)恰好需要停止的理由是:

  • \(i\) 的最小质因数肯定是 \(prime_j\)

如果 \(i\) 的最小质因数是 \(prime_s\) ,那么 \(prime_s\) 更早被枚举到(因为我们从小到大枚举质数),当时就会 break

既然 \(i\) 的最小质因数是 \(prime_j\) ,那么 \(i \times prime_j\) 的最小质因数也是 \(prime_j\) 。所以,\(i*prime_j\) 是符合关于 \(prime_j\) “筛条件”的。

  • \(prime_s\)\(\leq i \times prime_j\) 的质数, \(i \times prime_s\) 的最小质因数是 \(prime_s\)

    如果是它的最小质因数是更小的质数 \(prime_t\),那么当然\(prime_t\) 更早被枚举到,当时就要 break

    这说明 \(j\) 之前(用 \(i \times prime_s\) 的方式去筛合数,使用的是最小质因数)都符合是符合关于 \(prime_s\) 的“筛条件”。

  • \(prime_l\)\(\geq i \times prime_j\) 的质数, \(i \times prime_l\) 的最小质因数是 \(prime_j\)

    因为 \(i\) 的最小质因数是 \(prime_j\),所以 \(i \times prime_l\) 也含有 \(prime_j\) 这个因数,所以其最小质因数也是 \(prime_j\)(新的质因数 \(prime_l\) 太大了

    这说明,如果 \(j\) 继续递增(将以 \(i \times prime_l\) 的方式去筛合数,没有使用最小质因数),是不符合“筛条件”的。

经过这个优化,欧筛的时间复杂度是 \(O(n)\)

posted @ 2021-11-19 17:30  yhang323  阅读(36)  评论(0)    收藏  举报