题解:AcWing 866 试除法判定质数
【题目来源】
AcWing:866 试除法判定质数 - AcWing题库
【题目描述】
给定 \(n\) 个正整数 \(a_i\),判定每个数是否是质数。
【输入】
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个正整数 \(a_i\)。
【输出】
共 \(n\) 行,其中第 \(i\) 行输出第 \(i\) 个正整数 \(a_i\) 是否为质数,是则输出 Yes,否则输出 No。
【输入样例】
2
2
6
【输出样例】
Yes
No
【核心思想】
-
问题分析:给定 \(n\) 个正整数 \(a_i\),需要逐一判定每个数是否为质数。质数的定义是大于 \(1\) 且仅能被 \(1\) 和自身整除的自然数,因此只需检查每个数是否存在除 \(1\) 和自身以外的因数。
-
算法选择:
- 试除法(Trial Division):对于待判定整数 \(x\),枚举所有可能的因数 \(i\)(\(2 \leq i \leq \sqrt{x}\)),若存在 \(i\) 整除 \(x\),则 \(x\) 为合数;否则为质数
- 根号优化:若 \(x\) 存在大于 \(\sqrt{x}\) 的因数 \(d\),则 \(x/d\) 必为小于 \(\sqrt{x}\) 的因数,因此只需枚举到 \(\sqrt{x}\) 即可
-
关键步骤:
- 读取输入:\(n\) 和 \(n\) 个正整数 \(a_i\)
- 判定函数
is_prime(x):- 若 \(x < 2\),直接返回
false - 枚举 \(i\) 从 \(2\) 到 \(\lfloor\sqrt{x}\rfloor\)(代码中常用
i \leq x / i避免溢出) - 若 \(x \bmod i = 0\),返回
false - 枚举结束仍未找到因数,返回
true
- 若 \(x < 2\),直接返回
- 逐数判定:对每个 \(a_i\) 调用判定函数,输出
Yes或No
-
时间/空间复杂度:
- 时间复杂度:\(O(n\sqrt{a_i})\),对每个数最多进行 \(\sqrt{a_i}\) 次取模判断
- 空间复杂度:\(O(1)\),仅使用常数额外空间
-
试除法的核心思想:
- 因数对称性:一个合数 \(x\) 的最小非平凡因数不超过 \(\sqrt{x}\),只需检查前半段即可覆盖所有可能的因数分解
- 边界安全写法:使用
i \leq x / i代替i * i \leq x可避免i^2溢出风险 - 最朴素的质数判定方法:思路直观、实现简单,适用于单次或少量查询场景
- 适用于数据范围较小(\(a_i \leq 10^{12}\))或查询次数不多的质数判定问题;对于大规模区间筛质数,应使用埃氏筛或线性筛
【算法标签】
质数
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n; // 输入数字的个数
// 判断一个数是否为质数
bool is_prime(int n)
{
// 小于2的数不是质数
if (n < 2)
return false;
// 检查从2到√n的因数
for (int i = 2; i <= n / i; i++)
{
// 如果n能被i整除,则不是质数
if (n % i == 0)
return false;
}
return true; // 否则是质数
}
int main()
{
// 输入数字的个数
cin >> n;
// 处理每个数字
for (int i = 1; i <= n; i++)
{
int x;
cin >> x; // 输入待判断的数字
// 判断并输出结果
if (is_prime(x))
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}
【运行结果】
2
2
Yes
6
No
浙公网安备 33010602011771号