题解:AcWing 866 试除法判定质数

【题目来源】

AcWing:866 试除法判定质数 - AcWing题库

【题目描述】

给定 \(n\) 个正整数 \(a_i\),判定每个数是否是质数。

【输入】

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一个正整数 \(a_i\)

【输出】

\(n\) 行,其中第 \(i\) 行输出第 \(i\) 个正整数 \(a_i\) 是否为质数,是则输出 Yes,否则输出 No

【输入样例】

2
2
6

【输出样例】

Yes
No

【核心思想】

  1. 问题分析:给定 \(n\) 个正整数 \(a_i\),需要逐一判定每个数是否为质数。质数的定义是大于 \(1\) 且仅能被 \(1\) 和自身整除的自然数,因此只需检查每个数是否存在除 \(1\) 和自身以外的因数。

  2. 算法选择

    • 试除法(Trial Division):对于待判定整数 \(x\),枚举所有可能的因数 \(i\)\(2 \leq i \leq \sqrt{x}\)),若存在 \(i\) 整除 \(x\),则 \(x\) 为合数;否则为质数
    • 根号优化:若 \(x\) 存在大于 \(\sqrt{x}\) 的因数 \(d\),则 \(x/d\) 必为小于 \(\sqrt{x}\) 的因数,因此只需枚举到 \(\sqrt{x}\) 即可
  3. 关键步骤

    • 读取输入\(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
    • 逐数判定:对每个 \(a_i\) 调用判定函数,输出 YesNo
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n\sqrt{a_i})\),对每个数最多进行 \(\sqrt{a_i}\) 次取模判断
    • 空间复杂度:\(O(1)\),仅使用常数额外空间
  5. 试除法的核心思想

    • 因数对称性:一个合数 \(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
posted @ 2026-06-21 11:24  团爸讲算法  阅读(7)  评论(0)    收藏  举报