N 以下の 素数の個数
- 数と計算
- 問題 08
- やさしい
- 目安 11 分
「n 以下の
本番の
入力は
問題
素数は、
Q 個の
入力の形式
Q
n_1
n_2
...
n_Q1 行目に
出力の形式
Q 行を
制約
- Q は、
1 以上 100000 以下の整数です - n_i は、
1 以上 2000000 以下の整数です - 同じ n_i が
何度出てくることもあります
入力と出力の例
例 1
10 以下の
入力
3 10 2 20
出力
4 1 8
例 2
1 は
入力
2 1 100
出力
0 25
ヒント
まだ開いていません
付箋は 3 枚。下の段ほど答えに近づきます
ヒント 2
ヒント 3答えに近い
全部の
先に
解答
質問の
Python
Python
import sys
from itertools import accumulate
data = sys.stdin.read().split()
q = int(data[0])
queries = list(map(int, data[1:1 + q]))
m = max(queries)
is_prime = bytearray([1]) * (m + 1)
is_prime[0] = 0
is_prime[1] = 0
p = 2
while p * p <= m:
if is_prime[p]:
is_prime[p * p::p] = bytes(len(range(p * p, m + 1, p)))
p += 1
count = list(accumulate(is_prime))
print("\n".join(str(count[n]) for n in queries))JavaScript
JavaScript
const data = require("fs").readFileSync(0, "utf8").split(/\s+/).filter(Boolean).map(Number);
const q = data[0];
const queries = data.slice(1, 1 + q);
let m = 0;
for (const n of queries) if (n > m) m = n;
const isPrime = new Uint8Array(m + 1).fill(1);
isPrime[0] = 0;
isPrime[1] = 0;
for (let p = 2; p * p <= m; p++) {
if (!isPrime[p]) continue;
for (let k = p * p; k <= m; k += p) isPrime[k] = 0;
}
const count = new Int32Array(m + 1);
for (let x = 1; x <= m; x++) count[x] = count[x - 1] + isPrime[x];
console.log(queries.map((n) => count[n]).join("\n"));計算量
ふるいは O(M log log M) で、
遅い
よく ある間違い
- 1 を
素数として 数えてしまう。 表の 0 番と 1 番は、 はじめに 素数でないに しておきます - 素数か
確かめる 割り算を xまで (あるいはx - 1まで) 回してしまい、 1 つの 数に x 回かかる。 割る 数は 2 乗して x を 越えない ところまでで足ります - ふるいの
表を、 質問ごとに 作り直してしまう。 表は 最大の n まで 1 回作れば、 全部の 質問に使えます - Python で
ふるいの 表を ふつうの リストで 持ち、 200 万回の 代入を 1 つずつ 書いて 遅くなる。 bytearrayとスライスへの 代入で まとめて 消すと 速く書けます
解答を動かした版 Python 3.12.14Node.js 22.23.4確認日 2026/10/31