개념

일정 범위 안의 소수를 여러 개 구할 때 사용합니다. 처음에는 22 이상의 수를 모두 소수 후보로 두고, 작은 소수부터 그 배수를 지웁니다.

배수 제거

22의 배수, 33의 배수, 55의 배수 순서로 표시합니다. 이미 지워진 수는 합성수이므로 그 수의 배수를 다시 순회할 필요가 없습니다.

소수 pp의 배수 표시는 p2p^2부터 시작합니다. 그보다 작은 배수 2p,3p,…,(p−1)p2p,3p,\dots,(p-1)p는 더 작은 소인수의 배수를 지우는 과정에서 처리됩니다. p2>Np^2>N이 되면 남아 있는 수들이 소수입니다.

2020 이하의 소수는 2,3,5,7,11,13,17,192,3,5,7,11,13,17,19입니다.

2020까지 구하는 과정을 보면 22의 배수인 4,6,8,…,204,6,8,\ldots,20을 먼저 지웁니다. 다음으로 남아 있는 33을 선택하고 9,12,15,189,12,15,18을 지웁니다. 3×2=63\times2=6은 22의 배수로 이미 지웠으므로 32=93^2=9부터 시작해도 됩니다. 다음 소수 55는 52>205^2>20이므로 여기서 끝납니다. 합성수라면 제곱근 이하의 소인수가 있어야 하므로, 남은 수 중 아직 지우지 못한 합성수는 없습니다.

이렇게 만든 표는 범위 안의 각 수가 소수인지 바로 확인할 수 있습니다. 질의가 많을수록 같은 수를 반복해서 나누어보는 계산을 줄일 수 있으며, 대신 범위 전체를 저장할 공간이 필요합니다.

복잡도

소수를 구할 범위의 최댓값을 NN이라고 합니다.

연산시간복잡도공간복잡도
체 전처리O(Nlog⁡log⁡N)O(N\log\log N)판별 표 O(N)O(N)
전처리 후 소수 여부 조회O(1)O(1)추가 O(1)O(1)

예제

문제

주어진 수 이하의 모든 소수를 구하여라.

입력

첫째 줄에 양의 정수 NN이 주어진다. 2≤N≤9 9992\le N\le9\,999이다.

출력

소수를 오름차순으로 한 줄에 공백을 사이에 두고 출력한다.

예제 입력

20

예제 출력

2 3 5 7 11 13 17 19

예제 코드

C++20

#include <iostream>
#include <algorithm>

using namespace std;

bool prime[10000];

int main() {
    int n, i, j;

    cin >> n;
    fill(prime, prime + n + 1, true);
    prime[0] = false;
    prime[1] = false;
    for (i = 2; i * i <= n; ++i) {
        if (prime[i]) {
            for (j = i * i; j <= n; j += i) {
                prime[j] = false;
            }
        }
    }

    for (i = 2; i <= n; ++i) {
        if (prime[i]) cout << i << ' ';
    }
    cout << '\n';
}