数论 - 质数筛法(埃式筛 + 线性筛)
给定一个正整数n,请你求出1~n中质数的个数。
输入格式
共一行,包含整数n。
输出格式
共一行,包含一个整数,表示1~n中质数的个数。
数据范围
1≤n≤106
输入样例:
8
输出样例:
4
1、埃式筛
做法:
对 每 一 个 质 数 , 筛 去 该 质 数 的 所 有 倍 数 即 可 。 对每一个质数,筛去该质数的所有倍数即可。 对每一个质数,筛去该质数的所有倍数即可。
i 从 2 开 始 依 次 遍 历 , 只 要 i 未 被 标 记 过 , 说 明 i 一 定 是 质 数 。 因 为 对 每 一 个 质 数 , 我 们 都 会 先 筛 去 其 倍 数 。 假 设 i 是 合 数 , 那 么 i 必 有 质 因 子 p i ( p i < i ) , i 必 然 已 经 被 筛 去 。 i从2开始依次遍历,只要i未被标记过,说明i一定是质数。因为对每一个质数,我们都会先筛去其倍数。\\假设i是合数,那么i必有质因子p_i(p_i<i),i必然已经被筛去。 i从2开始依次遍历,只要i未被标记过,说明i一定是质数。因为对每一个质数,我们都会先筛去其倍数。假设i是合数,那么i必有质因子pi(pi<i),i必然已经被筛去。
时 间 复 杂 度 : O ( n l o g ( l o g n ) ) 。 时间复杂度:O(nlog(logn))。 时间复杂度:O(nlog(logn))。
代码:
#include<iostream>
using namespace std;
const int N = 1e6+10;
int n,cnt,prime[N];
bool st[N];
void get_prime()
{
for(int i=2;i<=n;i++)
if(!st[i])
{
prime[cnt++]=i;
for(int j=i;j<=n;j+=i) st[j]=true;
}
}
int main()
{
cin>>n;
get_prime();
cout<<cnt<<endl;
return 0;
}
2、线性筛
核 心 思 路 : 每 个 合 数 均 会 被 其 最 小 质 因 子 筛 去 。 核心思路:每个合数均会被其最小质因子筛去。 核心思路:每个合数均会被其最小质因子筛去。
① 、 i 从 2 开 始 依 次 枚 举 , 只 要 i 未 被 筛 过 , 说 明 i 是 质 数 , 将 其 存 储 下 来 。 ①、i从2开始依次枚举, 只要i未被筛过,说明i是质数,将其存储下来。 ①、i从2开始依次枚举,只要i未被筛过,说明i是质数,将其存储下来。
② 、 从 前 到 后 依 次 枚 举 每 个 质 数 p j , 把 每 个 p j 的 i 倍 筛 去 , 直 到 枚 举 到 i 的 最 小 质 因 子 或 者 p j × i > n 。 ②、从前到后依次枚举每个质数p_j,把每个p_j的i倍筛去,直到枚举到i的最小质因子或者p_j×i>n。 ②、从前到后依次枚举每个质数pj,把每个pj的i倍筛去,直到枚举到i的最小质因子或者pj×i>n。
下 面 解 释 如 何 保 证 所 有 合 数 均 被 筛 去 : 下面解释如何保证所有合数均被筛去: 下面解释如何保证所有合数均被筛去:
对 于 任 意 合 数 , 均 对 应 一 个 最 小 质 因 子 p j 。 i 是 从 小 到 大 枚 举 的 , 那 么 所 有 最 小 质 因 子 是 p j 的 合 数 均 会 被 筛 去 。 对于任意合数,均对应一个最小质因子p_j。\\i是从小到大枚举的,那么所有最小质因子是p_j的合数均会被筛去。 对于任意合数,均对应一个最小质因子pj。i是从小到大枚举的,那么所有最小质因子是pj的合数均会被筛去。
① 、 若 i 是 质 数 , 将 依 次 筛 去 每 一 个 p j × i , 显 然 p j × i 的 最 小 质 因 子 也 是 p j , 因 为 循 环 顺 序 保 证 了 i > = p j 。 ①、若i是质数,将依次筛去每一个p_j×i,显然p_j×i的最小质因子也是p_j,因为循环顺序保证了i>=p_j。 ①、若i是质数,将依次筛去每一个pj×i,显然pj×i的最小质因子也是pj,因为循环顺序保证了i>=pj。
② 、 若 i 是 合 数 , 那 么 必 然 存 在 p j 是 i 的 最 小 质 因 子 , 就 已 经 在 i 枚 举 到 p j i 时 被 筛 去 了 。 ②、若i是合数,那么必然存在p_j是i的最小质因子,就已经在i枚举到\frac{p_j}{i}时被筛去了。 ②、若i是合数,那么必然存在pj是i的最小质因子,就已经在i枚举到ipj时被筛去了。
时 间 复 杂 度 O ( n ) 。 时间复杂度O(n)。 时间复杂度O(n)。
代码:
#include<iostream>
using namespace std;
const int N = 1e6+10;
int n,cnt,prime[N];
bool st[N];
void get_prime()
{
for(int i=2;i<=n;i++)
{
if(!st[i]) prime[cnt++]=i;
for(int j=0;prime[j]<=n/i;j++)
{
st[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
}
int main()
{
cin>>n;
get_prime();
cout<<cnt<<endl;
return 0;
}