• 线性筛素数(欧拉筛)


    线性筛是一个很基础的算法,但是我一直没学。直到一次考试,因为O(n√n)会超时,用了表筛,结果被卡了代码长度,于是开始学习欧拉筛。

    算法思路:

      对于每一个数(无论质数合数)x,筛掉所有小于x最小质因子的质数乘以x的数。比如对于77,它分解质因数是7*11,那么筛掉所有小于7的质数*77,筛掉2*77、3*77、5*77。

      好吧,是不是听起来太简单了。。。。没事,重点在证明。

    算法证明:

      首先我们要明确证明思路。如果要证明它是对的,只要保证两点:没用重复筛、没有漏筛

      1、没有重复筛。

        我们假设一个合数分解成p1*p2*p3,并且保证p1<p2<p3。我们知道,筛掉这个合数的机会有:p1和p2*p3,p2和p1*p3,p3和p1*p2。但我们知道,我们选择的那个质数必须小于那个合数的最小质因子。比如p2和p1*p3,因为p2>p1,所以这样是筛不到的。唯一会筛的是第一种:p1和p2*p3。

      2、没有漏筛。

      还是假设把这个合数分解质因数a*b*c,保证a<b<c然后我们设s=b*c,s肯定小于刚才那个合数,说明肯定对于它已经筛过,然后a肯定小于s,因为s=b*c,并且a是最小的因子。说明a*s也就是这个合数一定筛过。

    证明没看懂的直接看代码吧。。挺好背的。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cstdlib>
    #define in(a) a=read()
    #define REP(i,k,n) for(int i=k;i<=n;i++)
    using namespace std;
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar())
            if(ch=='-')
                f=-1;
        for(;isdigit(ch);ch=getchar())
            x=x*10+ch-'0';
        return x*f;
    }
    int prime[1000010],book[1000010];
    int n,ind;
    int main(){//计算1~n的素数
        in(n);
        REP(i,2,n){
            if(!book[i])  prime[++ind]=i;//如果没有筛过,记录素数
            REP(j,1,ind){//其中记录数组里的素数保证严格递增
                if(i*prime[j]>n)  break;//保证小于n,要不然没有意义
                book[i*prime[j]]=1;//筛去这个合数
                if(!i%prime[j])  break;//如果>=这个数的最小质因子,那就结束
            }
        }
        REP(i,1,ind)  printf("%d ",prime[i]);//输出
    }
  • 相关阅读:
    [洛谷P3369] 普通平衡树 Treap & Splay
    [NOIp2016] 组合数问题
    [洛谷P4777] [模板] 扩展中国剩余定理
    [洛谷P3384] [模板] 树链剖分
    [NOIp2017] 时间复杂度
    [bzoj3270] 博物馆
    [USACO06DEC] Milk Patterns
    [USACO5.1] Musical Themes
    后缀数组 模板+详解
    [HNOI2004] L语言
  • 原文地址:https://www.cnblogs.com/jason2003/p/9761296.html
Copyright © 2020-2023  润新知