准备从头开始进行算法中数学知识的学习。
题目描述
给定一个正整数 ,请你求出 中质数的个数。
输入格式
共一行,包含整数 。
输出格式
共一行,包含一个整数,表示 中质数的个数。
数据范围
输入样例:
8
输出样例:
4
题目分析
这是一道数论的经典题目,主要知识点是关于质数的应用。
根据题目所给的数据范围的大小,我们将进行不同算法的选择。
O(n*sqrt(n))
这个方法就是最基础的枚举法,对于从 中的所有数,我们统一用一个方法进行质数的判断。即对于一个数 ,我们从 开始枚举到 ,若这个范围区间的数存在被 整除的数,则证明 不是质数,反之则为质数。
O(nloglogn)
接下来介绍埃氏筛法。
首先我们知道一个数 只能被小于 的数整除,而且在所有能整除 的数中,最小的那个是一个质数,其余的数同样被那个最小的质数整除。在此前提下给定求解的范围 ,我们从 开始枚举到 ,每次枚举当前数的倍数并递增枚举,并对除第一次枚举的数做标记,意为其可以被第一个数整除,即不是质数;在进行下一次枚举时对不是质数的数直接跳过即可。
欧拉筛法(线性筛)
线性筛法是埃氏筛法的一个优化,其是针对埃氏筛法会多次筛去合数的一个改变。
其核心思想为 一定会且只会被其最小质因子筛掉,具体表现在有两个方面:
- 一个数一定会被其最小质因子筛去。对于数 ,设其最小质因子为 ,在枚举到 之前一定会枚举到 ,即其一定会被筛去。
- 一个数只会被其最小质因子筛去。若当前枚举到 ,质数枚举到 ,若 ,意味着 是 的最小质因子,则直接跳出。
Accept代码
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int n, cnt;
int primes[N];
bool st[N];
int main()
{
cin >> n;
for (int i = 2; i <= n; i ++)
{
if (!st[i]) primes[cnt ++] = i;
for (int j = 0; primes[j] <= n / i; j ++)
{
st[i * primes[j]] = true;
if (i % primes[j] == 0) break;
}
}
cout << cnt;
return 0;
}