用埃拉托斯特尼筛法在 O(n log log n) 时间内统计 [2, n] 中的素数个数。
OJ: roj
题目 ID: 1151
难度:入门
标签:数论素数筛法
创建: 2026-09-29 21:02
更新: 2026-10-05 03:32
后置题目
roj 3668报数A 教的埃氏筛「枚举筛子、标记其全部倍数」这一步被 B 直接搬用:把筛子从素数换成含 7 的数,只是把倍数改标为禁报,B 原文也点明与埃氏筛结构一模一样roj 1623「一本通 6.2 练习 4」Sherlock and His GirlfriendB 的 prime_table 直接复用 A 教的埃氏筛「p 从 p^2 起整片划掉倍数」,只是筛区间换成价值上界 n+1,再叠加 A 未教的「冲突边必是质数—合数、二分染色数退化为 1 或 2」这一图论观察,属在 A 的筛法台阶上叠加额外构造流程。roj 1621「一本通 6.2 练习 2」轻拍牛头B 复用 A 教的埃氏筛倍数枚举:把 A 中「枚举 p 的倍数并标记」迁移为「对每个出现数字枚举其倍数并累加 cnt」,再叠加值域统计与约数和转化。noi_openjudge ch0105-44第n小的质数B 的第 n 小质数解法直接复用 A 教的埃氏筛「从 p 的平方起标记倍数」这一具体步骤,只是把统计素数个数改为按下标取第 n 个质数,额外确定 104729 上界。noi_openjudge ch0112-10素数对B 的 Python 解法直接复用 A 教的埃氏筛(平方起标记合数)先打出素数表,再叠加枚举差为 2 的素数对
题目描述
求 10,对应输出 4。
思路
埃拉托斯特尼筛:从小到大枚举素数
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-07-07 10:00
# update_at: 2026-07-07 10:00
import sys
def sieve_count(n: int) -> int:
"""埃拉托斯特尼筛:返回 [2, n] 中素数个数。"""
if n < 2:
return 0
is_prime = bytearray(b"\x01") * (n + 1) # 1 表示待判定为素数
is_prime[0:2] = b"\x00\x00" # 0 和 1 不是素数
for p in range(2, int(n ** 0.5) + 1):
if is_prime[p]:
step = p
start = p * p
is_prime[start:n + 1:step] = b"\x00" * ((n - start) // step + 1)
return is_prime.count(1)
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
n = next(data)
print(sieve_count(n))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 03:32
* update_at: 2026-10-05 03:32
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 50005;
bool is_composite[MAXN]; // is_composite[i] 为 true 表示 i 已被筛掉,是合数
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll n;
cin >> n;
// 埃拉托斯特尼筛:从小到大枚举素数 p,把 p*p, p*p+p, ... 标记为合数
for (ll p = 2; p * p <= n; p++) {
if (is_composite[p]) {
continue;
}
for (ll j = p * p; j <= n; j += p) {
is_composite[j] = true;
}
}
// 统计 [2, n] 中未被标记的数的个数,即素数个数
ll answer = 0;
for (ll i = 2; i <= n; i++) {
if (!is_composite[i]) {
answer++;
}
}
cout << answer << endl;
return 0;
}