文章目录
- 一、质数
- 二、质数的判定——试除法
- 1. 实现思路
- 2. 实现代码
- 三、分解质因数——试除法
- 1. 实现思路
- 2. 实现代码
- 四、筛质数
- 1. 朴素筛法
- 1.1 实现思路
- 1.2 实现代码
- 2. 线性筛法
- 2.1 实现思路
- 2.2 实现代码
一、质数
- 质数又称素数。一个大于
的自然数,除了
- 质数具有如下性质:
- (1) 质数
的约数只有两个:
和
。
- (2) 初等数学基本定理:任一大于
- (3) 质数的个数是无限的。
- (4) 若
为正整数,在
到
- (5) 所有大于
的质数中,个位数只有
。
二、质数的判定——试除法
题目描述
给定 个正整数
,判定每个数是否是质数。
输入格式
第一行包含整数 。
接下来 行,每行包含一个正整数
。
输出格式
共 行,其中第
行输出第
个正整数
是否为质数,是则输出
Yes
,否则输出 No
。
数据范围
输入样例
2
2
6
输出样例
Yes
No
具体实现
1. 实现思路
- 暴力写法:可以从质数的常规定义出发,首先判断这个数是不是大于等于 2 的,然后判断在 2 到这个数之间是否还有别的约数,如果没有,那么这个数就是质数,反之就不是质数。该暴力写法的时间复杂度是
。
- 对上述暴力写法进行优化时,需要利用到质数的一个性质。
- 当
可以整除
时,显然,
也可以整除
。例如,当
时,
是
的约数,
也是
- 因此,在我们枚举的过程中,只需要枚举其中较小的一个即可,优化过后的时间复杂度是
。
2. 实现代码
#include <bits/stdc++.h>
using namespace std;
bool is_prime(int x)
{
//判断这个数是否大于等于 2
if (x < 2)
{
return false;
}
//判断是否还有别的约束
for (int i = 2; i <= x / i; i ++ )
{
if (x % i == 0)
{
return false;
}
}
return true;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
cin >> x;
if (is_prime(x))
{
puts("Yes");
}
else
{
puts("No");
}
}
return 0;
}
三、分解质因数——试除法
题目描述
给定 个正整数
,将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。
输入格式
第一行包含整数 。
接下来 行,每行包含一个正整数
。
输出格式
对于每个正整数 ,按照从小到大的顺序输出其分解质因数后,每个质因数的底数和指数,每个底数和指数占一行。
每个正整数的质因数全部输出完毕后,输出一个空行。
数据范围
输入样例
2
6
8
输出样例
2 1
3 1
(空行)
2 3
(空行)
具体实现
1. 实现思路
- 我们需要注意的是,质因数的底数必须是质数。
- 暴力写法:从小到大枚举
的所有质因数,如果
模
等于
,就求出
void divide(int x)
{
for (int i = 2; i <= x; i ++ )
{
if (x % i == 0) //i一定是质数
{
int s = 0;
while (x % i == 0)
{
x /= i;
s ++ ;
}
cout << i << ' ' << s << endl;
}
}
}
- 随后在对
进行是否大于
- 对上述写法进行优化,我们需要使用质数的如下性质。
的质因子最多只包含一个大于
的质数。如果有两个,这两个因子的乘积就会大于
,矛盾。
- 然后,我们
从
遍历到
。 用
,如果余数为
,则
表示质因子
的指数,
为
,则
,
- 最后检查是否有大于
- 时间复杂度便会从
降低到
。
2. 实现代码
#include <bits/stdc++.h>
using namespace std;
void divide(int x)
{
for (int i = 2; i <= x / i; i ++ )
{
if (x % i == 0) //i一定是质数
{
int s = 0;
while (x % i == 0)
{
x /= i;
s ++ ;
}
cout << i << ' ' << s << endl;
}
}
if (x > 1)
{
cout << x << ' ' << 1 << endl;
}
cout << endl;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
cin >> x;
divide(x);
}
return 0;
}
四、筛质数
题目描述
给定一个正整数 ,请你求出
输入格式
共一行,包含整数 。
输出格式
共一行,包含一个整数,表示
数据范围
输入样例
8
输出样例
4
具体实现
1. 朴素筛法
1.1 实现思路
- 首先,我们将所有的数放入一个数组当中,然后从前往后观察,依次将每一个数的倍数删除掉。
- 经过这样筛选过后,剩下的数就都是质数。
1.2 实现代码
#include <bits/stdc++.h>
using namespace std;
const int N= 1000010;
//cnt表示质数的个数
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (st[i])
{
//跳出本次循环
continue;
}
//primes[]数组存储质数
primes[cnt ++ ] = i;
//去除倍数
for (int j = i + i; j <= n; j += i)
{
st[j] = true;
}
}
}
int main()
{
int n;
cin >> n;
get_primes(n);
cout << cnt << endl;
return 0;
}
2. 线性筛法
2.1 实现思路
- 算法核心:
- 当
为一个合数的时候,如果
比
- 判断
,
一定是
的最小质因子,
也一定是
- 判断
,
一定小于
的所有质因子,
也一定是
- 于一个合数
,假设
是
的最小质因子,当
枚举到
2.2 实现代码
#include <bits/stdc++.h>
using namespace std;
const int N= 1000010;
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!st[i])
{
primes[cnt ++ ] = i;
}
for (int j = 0; primes[j] <= n / i; j ++ )
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) //primes[j]一定是i的最小质因子
{
break;
}
}
}
}
int main()
{
int n;
cin >> n;
get_primes(n);
cout << cnt << endl;
return 0;
}