본문으로 건너뛰기
김신건의 로그

소인수분해 (Prime Factorization)

· 수정 · 📖 약 3분 · 747자/단어 #algorithm #math #prime-factorization #number-theory
prime factorization, 소인수분해, 소인수 분해, prime-factorization

정의

소인수분해 (Prime Factorization) 는 양의 정수 N을 소수들의 곱으로 유일하게 나타내는 것. N = p₁^a₁ · p₂^a₂ · … · pₖ^aₖ. 시행 나눗셈 O(√N), 에라토스테네스 체로 O(log N) 전처리, Pollard rho O(N^1/4) 가 대표적.

문제 상황과 동기

정수 N (10^12 이하) 의 소인수를 전부 구하라.

  • naive (2..N-1 순회): O(N). N=10^12 면 timeout.
  • 시행 나눗셈 (Trial Division): 2부터 √N 까지 나누기. O(√N). N=10^12 면 10^6.
  • 체로 빠른 분해: N 이하 소수 미리 체로 구해 두면, O(π(√N)) ≈ O(√N / log N).
  • Pollard rho: 확률적 O(N^1/4). N=10^18 도 몇 초 안에 분해.

핵심 통찰: N 이 합성수면 √N 이하 소인수가 반드시 하나 존재. 작은 소인수부터 제거하면 나머지는 큰 소수 하나만 남음.

시각화

핵심 아이디어

시행 나눗셈

N 을 2, 3, 5, 7, ... 순서대로 나눔.
나누어떨어지면 그 소수를 기록하고, N /= p.
√N 이하 소인수 전부 제거 후, N > 1 이면 N 자체가 소수.

체로 빠른 분해

N 이하 소수를 에라토스테네스 체로 미리 구해 두면,
소인수분해 시 체에서 뽑은 소수만 시도 → O(π(√N)).

Pollard rho

GCD 기반 확률적 방법. f(x) = x² + c (mod N) 사이클 찾기.

x₀ = 2, y₀ = 2
repeat:
    x = f(x), y = f(f(y))
    d = gcd(|x - y|, N)
    if 1 < d < N: return d  // 비자명 약수
재귀적으로 d, N/d 분해.

알고리즘

Trial Division (O(√N))

factorize(N):
    res = []
    for p = 2..sqrt(N):
        if p * p > N: break
        while N % p == 0:
            res.append(p)
            N /= p
    if N > 1: res.append(N)
    return res

Optimized Trial (6k±1)

factorize(N):
    res = []
    for p in [2, 3]:
        while N % p == 0:
            res.append(p)
            N /= p
    i = 5
    while i * i <= N:
        for p in [i, i+2]:  // 6k-1, 6k+1
            while N % p == 0:
                res.append(p)
                N /= p
        i += 6
    if N > 1: res.append(N)
    return res

Pollard rho (확률적, 큰 N)

pollard_rho(N):
    if is_prime(N): return [N]
    if N % 2 == 0:
        return [2] + factorize(N / 2)
    x, y, d = 2, 2, 1
    f = lambda x: (x*x + 1) % N
    while d == 1:
        x = f(x)
        y = f(f(y))
        d = gcd(abs(x - y), N)
    if d == N: retry with different c
    return factorize(d) + factorize(N / d)

구현

// Trial division O(√N), 6k±1 최적화
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

vector<ll> factorize(ll n) {
  vector<ll> res;
  for (ll p : {2, 3}) {
      while (n % p == 0) {
          res.push_back(p);
          n /= p;
      }
  }
  for (ll i = 5; i * i <= n; i += 6) {
      for (ll p : {i, i + 2}) {
          while (n % p == 0) {
              res.push_back(p);
              n /= p;
          }
      }
  }
  if (n > 1) res.push_back(n);
  return res;
}

int main() {
  ll n; cin >> n;
  auto factors = factorize(n);
  for (ll p : factors) cout << p << " ";
  cout << "\n";
}
stdin
60
결과
2 2 3 5

복잡도

항목시행 나눗셈체로 전처리Pollard rho
시간 (최악)O(√N)O(N log log N) + O(π(√N))O(N^1/4)
공간O(1)O(N)O(log N)
범위N < 10^12N < 10^7N < 10^18

변형

방법특징용도
Smallest prime factor (SPF)O(N log log N) 전처리, O(log N) 분해N 이하 여러 수 분해
Wheel factorization2,3,5 체의 회전 패턴6k±1 보다 빠름
Quadratic sieveO(exp(√(log N log log N)))RSA 크기 (100자리~)
Pollard p-1smooth p-1 소인수 특화특수 N

함정

1. √N 이후 N > 1

for (ll i = 2; i * i <= n; i++) ...
if (n > 1) res.push_back(n);  // 빼먹으면 큰 소인수 누락

2. long long 범위

N=10^18 의 소인수는 10^9 초과 가능. int 로 저장하면 오버플로우.

3. Pollard rho 무한 루프

gcd(|x-y|, N) 가 계속 1 또는 N 이면 c 를 바꿔 재시도. 보통 c=1, 2, … 순회.

4. 중복 소인수

N=12=2²·3. 결과는 [2, 2, 3]. map<ll, int> 로 (소인수, 지수) 저장도 가능.

BOJ 연습 문제

번호제목정답률링크
BOJ 11653소인수분해-kokoa-lab
BOJ 4149큰 수 소인수분해-kokoa-lab
BOJ 1016제곱 ㄴㄴ 수-kokoa-lab
BOJ 2factorization--kokoa-lab

참고

이 글의 용어 (3개)
소수 판정 (Primality Test)algorithm
정의 소수 판정 (Primality Test) 은 주어진 정수 N이 소수인지 합성수인지 판별하는 알고리즘. 시행 나눗셈 (Trial Division) O(√N), 확률적 Ferm…
에라토스테네스의 체 (Sieve of Eratosthenes)algorithm
정의 에라토스테네스의 체 (Sieve of Eratosthenes) 는 1부터 N 까지의 모든 소수를 O(N log log N) 에 찾는 고대 그리스 알고리즘. 기원전 240 년…
유클리드 호제법 (Euclidean Algorithm)algorithm
정의 유클리드 호제법 (Euclidean Algorithm) 은 두 정수 a, b 의 최대공약수 (GCD, Greatest Common Divisor) 를 O(log min(a,…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기