| 문제 | 난이도 | 핵심 |
|---|---|---|
| 1929번 — 소수 구하기 | 실버 III | 기본 구현 |
| 2960번 — 에라토스테네스의 체 | 브론즈 I | K번째 지워지는 수 |
| 6588번 — 골드바흐의 추측 | 실버 I | 소수 목록 활용 |
N 이하의 모든 소수를 찾는 알고리즘이다. 핵심 아이디어는 단 하나다.
소수의 배수는 소수가 아니다.
2부터 시작해서 소수를 발견할 때마다 그 배수를 전부 제거한다. 남은 수가 모두 소수다.
N = 16 기준
| 단계 | 기준수 p | p² | 제거 대상 | 이유 |
|---|---|---|---|---|
| 1 | 2 | 4 | 4, 6, 8, 10, 12, 14, 16 | 2의 배수 |
| 2 | 3 | 9 | 9, 15 | 3의 배수 (6, 12는 이미 제거됨) |
| 3 | 4 | 16 | skip | 4는 합성수 (2가 이미 처리) |
| 4 | 5 | 25 | 루프 종료 | 5² = 25 > 16 |
최종 소수: 2, 3, 5, 7, 11, 13
√N 이상의 수의 배수는 더 작은 소수가 이미 처리했기 때문이다.
p² 미만의 배수는 더 작은 소수가 이미 제거했기 때문이다.
boolean[] isComposite = new boolean[N + 1]; // 합성수면 true
for (int p = 2; p * p <= N; p++) { // p를 2부터 √N까지
if (!isComposite[p]) { // p가 소수라면
for (int m = p * p; m <= N; m += p) { // p²부터 p씩 건너뛰며
isComposite[m] = true; // 배수를 합성수로 표시
}
}
}
// isComposite[i] == false 인 i (2 이상) 가 소수
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
StringBuilder sb = new StringBuilder();
int M = Integer.parseInt(st.nextToken());
int N = Integer.parseInt(st.nextToken());
boolean[] isComposite = new boolean[N + 1];
for (int p = 2; p * p <= N; p++) {
if (!isComposite[p]) {
for (int m = p * p; m <= N; m += p) {
isComposite[m] = true;
}
}
}
for (int i = M; i <= N; i++) {
if (i >= 2 && !isComposite[i]) { // 2 이상이면서 합성수가 아닌 것
sb.append(i).append("\n");
}
}
System.out.print(sb);
}
}
| 방법 | 시간복잡도 |
|---|---|
| 단순 소수 판별 (매번 계산) | O(N√N) |
| 에라토스테네스의 체 | O(N log log N) |
N이 클수록 차이가 극적으로 벌어진다. N = 1,000,000 이상이면 반드시 체를 사용해야 한다.
i >= 2 조건을 반드시 확인한다.isComposite 배열은 N + 1 크기로 선언한다 (인덱스 N까지 사용).p * p가 int 범위를 초과할 수 있는 경우 (long) p * p로 캐스팅한다.