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

题目

给定一个正整数 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;
}
相关推荐
Code_Shark8 分钟前
AtCoder Beginner Contest 426 题解
数据结构·c++·算法·数学建模·青少年编程
仰泳的熊猫10 分钟前
LeetCode:698. 划分为k个相等的子集
数据结构·c++·算法·leetcode
豐儀麟阁贵12 分钟前
4.5数组排序算法
java·开发语言·数据结构·算法·排序算法
xlq2232213 分钟前
7(内存管理)(上)(了解)
c++
Shinom1ya_41 分钟前
算法 day 32
算法
WBluuue2 小时前
数据结构与算法:摩尔投票算法
c++·算法·leetcode
柯一梦2 小时前
深入解析C++ String类的实现奥秘
c++
文火冰糖的硅基工坊3 小时前
[人工智能-大模型-66]:模型层技术 - 两种编程范式:数学函数式编程与逻辑推理式编程,构建起截然不同的智能系统。
人工智能·神经网络·算法·1024程序员节
蜗牛沐雨3 小时前
详解c++中的文件流
c++·1024程序员节
im_AMBER3 小时前
Leetcode 34
算法·leetcode