zoukankan      html  css  js  c++  java
  • 线性素数筛模板+理解

    线性筛其实NOIp2017之前打过线性筛板子,不过那时候就没理解,临阵磨枪顾不了那么多。

    学习数论的时候用到了,又看了一遍。作为一个性子比较急的人找了好几个博客都看不下去,因此花了很长时间才搞懂。

    O(sqrt(n))判断n是不是质数就不多赘述了。素数筛之所以叫“筛”是因为它的基本思想是对于1-n批量判素数,由当前已知素数筛去后面的是该素数倍数的合数,以此剩下质数。因此,根据这一基本思想,我们可以初步写出一种粗劣的素数筛算法:

    int n;
    const int sz=1e6+5;
    bool h[sz]={0};//h[i]=0表示i是质数,反之不是
    int z[sz],len;//z用于储存已知素数,len表示已知素数的个数
    h[1]=1;
    for(int i=2;i<=n;i++){
        if(h[i]==0)z[++len]=i;
        for(int j=1;j<=len&&z[j]*i<=n;j++)h[z[j]*i]=1;
    }    

    然后大家会发现,n一大这个算法的效率就非常呵呵了……

    尝试优化这个算法。

    分析可以发现,这个算法的效率之所以会低,是因为同一个数有很多质因子,因此会被筛很多遍。如果我们可以让一个数只被筛一次,就可以保证效率优化到O(n)。(这不是废话吗摔)

    那么,如何让一个数只被筛一次呢?可以考虑只用这个数最小的质数或者最大的质数去筛这个数。我们的原算法是,对于素数p,晒去p*x(x是大于1的正整数),若p是(p*x)的最小质因数,只要使得p不大于x中的所有质因数即可。原算法可以看作是枚举x,对于每个x从小到大枚举p,我们只要在p增大到恰为x的最小质因数时去枚举下一个x即可。

    代码如下:

    int n;
    const int sz=1e6+5;
    bool h[sz]={0};//h[i]=0表示i是质数,反之不是
    int z[sz],len;//z用于储存已知素数,len表示已知素数的个数
    h[1]=1;
    for(int i=2;i<=n;i++){
        if(h[i]==0)z[++len]=i;
        for(int j=1;j<=len&&z[j]*i<=n;j++){
            h[z[j]*i]=1;
            if(i%z[j]==0)break;
        }
    }    
    日常写错……欢迎指正 QQ:2960005671 邮箱:bleavescoder@163.com
  • 相关阅读:
    深度学习GPU集群管理软件 OpenPAI 简介
    图片加数字盲水印
    Kubernetes核心概念简介
    一文详解 Linux 系统常用监控工具(top,htop,iotop,iftop)
    【OfficeWebViewer】在线预览Word,Excel~
    【Java】大文本字符串滤重的简单方案
    Java应用集群下的定时任务处理方案(mysql)
    《将博客搬至CSDN》
    [转]Fiddler抓取Android真机上的HTTPS包
    [Java Collection]List分组之简单应用.
  • 原文地址:https://www.cnblogs.com/BLeaves/p/8641120.html
Copyright © 2011-2022 走看看