第?个质数(埃氏筛算法)

题目:

给定一个质数,求出这个质数是第几个质数。

输入格式:

第一行一个正整数n(1≤n≤105),

接下来n行,每行一个质数p(2≤p≤107)。

输出格式:

输出n行,每行输出一个正整数。

输入样例:

3

2

3

5

输出样例:

1

2

3

所用算法详解:

埃氏筛(Eratosthenes筛法)详解

算法原理

埃氏筛是一种高效找出一定范围内所有质数的算法。它的核心思想是:

质数的倍数一定不是质数(除了质数本身)。

算法步骤

  1. 假设我们想找出 1 到 N 之间的所有质数

  2. 先假设所有数都是质数(标记为1)

  3. 从2开始:

    如果当前数是质数,它的倍数(2倍、3倍...)都不是质数,将它们标记为非质数

  4. 重复这个过程直到 N

AC代码

c 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"

const int MAXN = 10000000;
int is_prime[MAXN + 10] = {0};  // 0表示未处理,正数表示质数序号,-1表示合数
int n;

void init() {
    int cnt = 1;
    for (int i = 2; i <= MAXN; i++) {
        if (is_prime[i] == 0) {  // i是质数
            is_prime[i] = cnt;    // 记录这是第cnt个质数
            cnt++;
            // 从 i*i 开始标记合数
            for (int j = i; j <= MAXN / i; j++) {
                is_prime[i * j] = -1;  // 标记为合数
            }
        }
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n;
    init();
    
    for (int i = 1; i <= n; i++) {
        int p;
        cin >> p;
        cout << is_prime[p];
        if (i != n) cout << endl;
    }
    
    return 0;
}

代码逐行讲解

c 复制代码
int is_prime[MAXN + 10] = {0};  // 0表示未处理,正数表示质数序号,-1表示合数

void init() { 
    int cnt = 1;  // 质数计数器
    
    // 从2开始遍历
    for (int i = 2; i <= MAXN; ++i) { 
        if (is_prime[i] == 0) {  // 如果i是质数(未被处理)
            is_prime[i] = cnt;    // 记录这是第cnt个质数
            cnt++;                // 计数器加1
            
            // 从 i*i 开始标记i的所有倍数为合数
            for (int j = i; j <= MAXN / i; j++) { 
                is_prime[i * j] = -1;  // 标记为合数
            } 
        } 
    } 
}

运行过程示例

假设我们要找前几个质数(以10为例):

初始状态:

c 复制代码
数字: 1 2 3 4 5 6 7 8 9 10
标记: 1 1 1 1 1 1 1 1 1 1  (1表示质数)

处理 i=2

  • 2是质数 → 标记为第1个质数

  • 删除2的倍数:4、6、8、10标记为0

c 复制代码
数字: 1 2 3 4 5 6 7 8 9 10
标记: 0 1 1 0 1 0 1 0 1 0

处理 i=3

  • 3是质数 → 标记为第2个质数

  • 删除3的倍数:6、9标记为0

c 复制代码
数字: 1 2 3 4 5 6 7 8 9 10
标记: 0 1 2 0 1 0 1 0 0 0

处理 i=4 :已经被标记为0,跳过
处理 i=5:5是质数 → 标记为第3个质数

c 复制代码
数字: 1 2 3 4 5 6 7 8 9 10
标记: 0 1 2 0 3 0 1 0 0 0

以此类推...

为什么这样高效?

  • 时间复杂度:O(n log log n),接近线性

  • 避免了每个数都要做质数判断的重复计算

  • 一次计算,多次查询(适合本题需要处理多个质数查询)

针对本题的优化

本题中:

  • 需要查询 n 个质数的序号

  • 质数范围是 2 ≤ p ≤ 10^7

  • 用埃氏筛可以一次性计算出所有质数及其序号

代码执行流程

  1. init() 预处理:计算出所有质数的序号

  2. 对于每个输入的质数 x

  3. 直接输出 is_prime[x] 即可得到它的序号

比如输入5,is_prime[5] = 3,直接输出3。

这种方法的优点是:

  • 预处理:只需要一次计算

  • 查询:O(1) 时间复杂度

  • 空间换时间:用数组存储结果

相关推荐
码匠许师傅6 分钟前
【C++三方组件】cxxopts:轻量首选的命令行解析
c++
hansang_IR18 分钟前
【讲解】CSP-S2026 第一轮初赛
c++·算法
hanlin0320 分钟前
刷题笔记:力扣第76题-最小覆盖子串
笔记·算法·leetcode
Zane199422 分钟前
比较排序跑不出O(nlogn)是数学上证明过的,计数、桶、基数排序凭什么能绕开这堵墙
算法·排序算法
tiger86523 分钟前
大语言模型面试和题解,梳理中国主流开源 LLM 系列的发展脉络、技术路线与工程取舍
人工智能·gpt·深度学习·算法·自然语言处理·面试·transformer
Methy27 分钟前
IoTHub半个月崩了五次?都是裸rethrow惹的祸
服务器·c++·后端
我不会起名字32236 分钟前
一天一道力扣Hot100(36):深度优先算法---组合总和
数据结构·c++·后端·python·算法·go
纪念 22940 分钟前
c++类和对象(四)
开发语言·c++
汉克老师1 小时前
GESP2026年9月认证C++六级( 第三部分编程题(2、分树规划))精讲
c++·gesp·小学生·学c++编程
学生小羊1 小时前
C++ 初阶 学习博客
c语言·c++·c++与c语言的区别·c++基础学习