线性筛质数笔记

Published on7/29/2025
Created on 12/17/2021

分配存储

核心思想

通过

某一合数 c 的最小质因数 p ×任意数 k = c\text{某一合数}\ c\ \text{的最小质因数}\ p\ \times\text{任意数}\ k\ =\ c

筛去所有 nn 以内的合数,留下的就是质数。 枚举 kk ,再对每个 kk 枚举不大于其的质数 pip_i,若中途发现某一 pikp_i\nmid k,对于所有之后要枚举的 pjp_jpipjkp_i\mid p_jk,必有一质因数小于枚举中的质数 pjp_j,所以肯定会被重复枚举,处理完 pip_i 后直接退出该层的循环即可。 即:

//....
if(i % p[j] == 0) break;

算法步骤

最后prime[]数组即是从小到大的质数列表。

参考代码

#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
//---//
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

typedef unsigned int u;
typedef long long ll;
typedef unsigned long long llu;

#define rep(i, a, b) for (ll i = a; i < b; i++)
#define REP(i, a, b) for (ll i = a; i <= b; i++)
#define per(i, b, a) for (ll i = b; i >= a; i--)

bool isp[100000005];
ll p[10000005], cnt = 0;

void getp(ll n) {
  memset(isp, true, sizeof(isp));
  isp[1] = false;
  REP(i, 2, n) {
    if (isp[i]) p[++cnt] = i;
    REP(j, 1, cnt) {
      if (i * p[j] > n) break;
      isp[i * p[j]] = false;
      if (i % p[j] == 0) break;
    }
  }
}

signed main() {
  ll n, q, k;
  scanf("%lld%lld", &n, &q);
  getp(n);
  while (q--) {
    scanf("%lld", &k);
    printf("%lld\n", p[k]);
  }
}

// https://www.luogu.com.cn/record/60897651