【算法】数论——筛质数(线性筛法)

题目

给定一个正整数 n,请你求出 1∼n 中质数的个数。

输入格式

共一行,包含整数 n。

输出格式

共一行,包含一个整数,表示 1∼n 中质数的个数。

数据范围

1 ≤ n ≤ 10^6

思路

朴素筛法
做法 :把2~(n-1)中的所有的数的倍数都标记上,最后没有被标记的数就是质数.
原理 :假定有一个数p未被2~(p-1)中的数标记过,那么说明,不存在2~(p-1)中的任何一个数的倍数是p,也就是说p不是2~(p-1)中的任何数的倍数,也就是说2~(p-1)中不存在p的约数,因此,根据质数的定义可知:p是质数.
时间复杂度:约为O(nlogn);

埃氏筛(稍加优化版的筛法)
质数定理 :1~n中有n/lnn个质数.
原理 :在朴素筛法的过程中只用质数项去筛.
时间复杂度:粗略估计:O(n).实际:O(nlog(logn)).1~n中,只计算质数项的话,"1/2+1/3+1/4+1/5+...+1/n"的大小约为log(logn)。

线性筛法 核心 :1~n内的合数p只会被其最小质因子筛掉.
原理:1~n之内的任何一个合数一定会被筛掉,而且筛的时候只用最小质因子来筛,然后每一个数都只有一个最小质因子,因此每个数都只会被筛一次,因此线性筛法是线性的.

注意:

1、枚举到 i 的最小质因子的时候就会停下来,即" if(i%primes[j]==0) break ; "。

2、因为从小到大枚举的所有质数,所以当" i % primes[j] != 0 "时,primes[ j ]一定小于 i 的最小质因子,而且 primes[j] 一定是primes[j] * i的最小质因子。

3、关于for循环的解释:

注:首先要把握住一个重点:我们枚举的时候是从小到大枚举的所有质数

(1)当i%primes[j]==0时,因为是从小到大枚举的所有质数,所以primes[j]就是i的最小质因子,而primes[j]又是其本身primes[j]的最小质因子,因此当i%primes[j]==0时,primes[j]是primes[j] * i的最小质因子。

(2)当 i%primes[j]!=0 时,因为是从小到大枚举的所有质数,且此时并没有出现过有质数满足i%primes[j] == 0,因此此时的primes[j]一定小于i的最小质因子,而primes[j]又是其本身primes[j]的最小质因子,所以当i%primes[j]!=0时,primes[j]也是primes[j] * i的最小质因子。

(3)综合1,2得知,在内层for循环里面无论何时,primes[j]都是primes[j] * i的最小质因子,因此 "st[primes[j * i] = true"语句就是用primes[j]i这个数的最小质因子来筛掉这个数。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
int primes[N],cnt;
bool st[N];// 储存该值i是不是为非质数

void get_primes(int n)
{
    for(int i = 2;i <= n; i ++)// 依次判断2~n是否为质数
    {
        if(!st[i]) primes[cnt ++] = i;// 如果该数是质数则将其储存起来,如果不是质数则不储存
        for(int j = 0;primes[j] <= n / i; j ++)// 筛掉是i的primes[j]倍的所有合数
        {
            st[primes[j] * i] = true;// 确保每个合数是被他最小的质因子筛掉的
            if(i % primes[j] == 0) break;// primes[j]一定是i的最小质因子
            //p[j]一定是i的最小质因子,pj也一定是pj*i的最小质因子
        }
    }
}

int main()
{
    int n;
    cin >> n;
    get_primes(n);
    cout << cnt << endl;
    return 0;
}
相关推荐
AI街潜水的八角2 分钟前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
白榆maple27 分钟前
(蓝桥杯C/C++)——基础算法(下)
算法
JSU_曾是此间年少32 分钟前
数据结构——线性表与链表
数据结构·c++·算法
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
何曾参静谧2 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
咕咕吖2 小时前
对称二叉树(力扣101)
算法·leetcode·职场和发展
九圣残炎2 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu3 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!3 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚3 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea