• 3.筛质数 质数


     筛质数的核心思想:

    先把所有数放进一个数组

    然后从前往后看,把每一个数的倍数删掉

    第一个数是2,就把所有2的倍数删掉,4,6,8,10,12

    第二个数是3,就把所有3的倍数删掉,6,9,12

    第二个数是4,就把所有4的倍数删掉,8,12

    第二个数是5,就把所有5的倍数删掉,10

    以此类推

     这样筛完之后,所有剩下的数就是质数

    证明:对于任何一个数p而言,如果p没有被删掉的话,就意味着从2到p - 1中的任何一个数,都没有把p删掉

    说明p不是2到p - 1中间任何一个数的倍数,也即2到p - 1中间不存在p的约数,所以p是一个质数

    质数定理:1 ~ n中,有n / ln (n)个质数

    线性筛:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1000010;
     4 int primes[N], cnt;
     5 bool st[N];
     6 void get_primes_1(int n) {
     7     //朴素筛法,时间复杂度近似O(n log n)
     8     for (int i = 2; i <= n; i++) { //从2到n枚举
     9         if (!st[i]) { //如果这个数没有被筛过的话,说明是一个质数
    10             primes[cnt++] = i;
    11         }
    12         //再把每一个数的倍数删掉
    13         for (int j = i + i; j <= n; j += i) { //最朴素方法
    14             st[j] = true;
    15         }
    16     }
    17 }
    18 void get_primes_2(int n) {
    19     //埃氏筛法,时间复杂度O(n log log n),近似O(n)
    20     for (int i = 2; i <= n; i++) { //从2到n枚举
    21         if (!st[i]) { //如果这个数没有被筛过的话,说明是一个质数
    22             primes[cnt++] = i;
    23             for (int j = i + i; j <= n; j += i) { //最朴素方法
    24                 st[j] = true;
    25             }
    26         }
    27         //并不需要把每一个数的倍数删掉,只把所有质数的倍数删掉就可以了
    28         //可以把循环放进判断里面去
    29     }
    30 }
    31 void get_primes_3(int n) {
    32     //线性筛法的基本思路也是一样的:争取把每个合数,用它的某一个质因子筛掉
    33     /*
    34         线性筛法的核心思路:每一个合数,只会被它的最小质因子筛掉
    35     */
    36     //线性筛法,时间复杂度O(n)
    37     for (int i = 2; i <= n; i++) { //从2到n枚举
    38         if (!st[i]) { //如果是一个质数的话
    39             primes[cnt++] = i; //加进去
    40         }
    41         //从小到大枚举所有质数
    42         for (int j = 0; primes[j] <= n / i; j++) {
    43             st[primes[j] * i] = true; 
    44             if (i % primes[j] == 0) { //当这句话成立时,就意味着primes[j]一定是i的最小质因子
    45                 break;
    46             }
    47         }
    48     }
    49 }
    50 /*
    51     当n = 1e6时,埃氏筛法和线性筛法运行时间差不多
    52     当n = 1e7时,线性筛法比埃氏筛法快一倍
    53 */
    54 int main() {
    55     int n;
    56     cin >> n;
    57     get_primes_3(n);
    58     cout << cnt << endl;
    59     return 0;
    60 }

     2020年8月2日复习更新,果然复习之后之前不明白的地方就容易明白了

    线性筛法里,42行primes[j] <= n / i,是primes[j] * i <= n的变形,防止越界

    然后把primes[j] * i筛掉

    然后我终于看明白别人的题解了

     1 void get_primes(){
     2     
     3     for(int i=2;i<=n;i++){
     4         if(!st[i]) primes[cnt++]=i;
     5         for(int j=0;primes[j]<=n/i;j++){//primes[j]<=n/i:变形一下得到——primes[j]*i<=n,把大于n的合数都筛了就没啥意义了
     6         
     7             st[primes[j]*i]=true;//用最小质因子去筛合数,一定有pj是pj * i的最小质因子
     8 
     9             //1)当i%primes[j]!=0时,说明此时遍历到的primes[j]不是i的质因子,那么只可能是此时的primes[j]<i的
    10             //最小质因子,所以primes[j]*i的最小质因子就是primes[j];
    11             //2)当有i%primes[j]==0时,说明i的最小质因子是primes[j],因此primes[j]*i的最小质因子也就应该是
    12             //prime[j],之后接着用st[primes[j+1]*i]=true去筛合数时,就不是用最小质因子去更新了,因为i有最小
    13             //质因子primes[j]<primes[j+1],此时的primes[j+1]不是primes[j+1]*i的最小质因子,此时就应该
    14             //退出循环,避免之后重复进行筛选。
    15             if(i%primes[j]==0) break;
    16         }
    17     }
    18 
    19 }
    20 
    21 作者:orzorz
    22 链接:https://www.acwing.com/solution/content/7950/
    23 来源:AcWing
    24 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    MongoDB学习(附录一) 安装mongodb3.6时碰到的问题
    详细图解mongodb下载、安装、配置与使用
    大数据时代的数据存储,非关系型数据库MongoDB
    python获取风和天气城市数据 ID
    智能车学习(二十一)——浅谈CCD交叉以及横线摆放
    智能车学习(二十)——浅谈C车硬连接与软连接
    智能车学习(十九)——硬件电路设计
    智能车学习(十八)——电机学习
    智能车学习(十七)——舵机学习
    智能车学习(十六)——CCD学习
  • 原文地址:https://www.cnblogs.com/fx1998/p/13415056.html
Copyright © 2020-2023  润新知