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

조화수 (Harmonic Number)

· 수정 · 📖 약 2분 · 705자/단어 #algorithm #math #harmonic-number #number-theory
harmonic number, 조화수, H_n, harmonic series, harmonic-number

정의

조화수 (Harmonic Number) H_n 은 자연수 n 에 대해 역수의 합 Σ_{k=1}^{n} 1/k 으로 정의. 점근적으로 H_n = ln n + γ + 1/(2n) - ... (γ ≈ 0.5772, 오일러-마스케로니 상수). 정수론과 알고리즘 분석에서 O(n log n) 의 log factor 가 사실은 H_n 에서 비롯.

문제 상황과 동기

n = 10^6 일 때 Σ_{k=1}^{n} ⌊n/k⌋ 또는 약수 배수 관계의 합.

  • naive (이중 루프): O(n²). n=10^5 면 10^10, 불가능.
  • 조화수 통찰: n/k 의 서로 다른 값은 O(√n) 개. 구간 나누기로 O(√n) 또는 O(n log n).

핵심 통찰: ⌊n/k⌋ 는 k 가 작을 때는 자주 변하지만, k 가 클 때는 천천히 변한다. 따라서 같은 몫을 갖는 구간 을 한 번에 처리할 수 있다.

시각화

핵심 아이디어

조화수 점화

H_0 = 0
H_n = H_{n-1} + 1/n

구간 나누기 (harmonic lemma)

⌊n/k⌋ 의 값이 같은 k 의 구간 [l, r]:

r = n / (n / l)

이 구간 내에서 ⌊n/k⌋ = q 로 일정. 합을 q × (r - l + 1) 로 O(1) 에 계산.

이 기법은 각 구간을 묶어서 O(√n) 번의 연산으로 모든 ⌊n/k⌋ 의 합을 구하게 해 준다.

약수 배수 합

Σ_{i=1}^{n} d(i) = Σ_{i=1}^{n} ⌊n/i⌋ = 2 Σ_{i=1}^{√n} ⌊n/i⌋ - (⌊√n⌋)²

알고리즘

harmonic_sum(n):
    sum = 0
    for i = 1..n:
        sum += 1.0 / i
    return sum

harmonic_floor_sum(n):        # Σ ⌊n/i⌋
    sum = 0
    l = 1
    while l <= n:
        q = n // l
        r = n // q
        sum += q * (r - l + 1)
        l = r + 1
    return sum

구현

// H_n 계산 + harmonic floor sum O(sqrt(n))
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

double harmonic(int n) {
  double h = 0;
  for (int i = 1; i <= n; i++) h += 1.0 / i;
  return h;
}

ll floor_sum(ll n) {
  ll sum = 0;
  for (ll l = 1, r; l <= n; l = r + 1) {
      ll q = n / l;
      r = n / q;
      sum += q * (r - l + 1);
  }
  return sum;
}

int main() {
  int n; cin >> n;
  cout << fixed << setprecision(10);
  cout << "H_" << n << " = " << harmonic(n) << "\n";
  cout << "Sigma n/i = " << floor_sum(n) << "\n";
  return 0;
}
stdin
10
결과
H_10 = 2.9289682540
Sigma n/i = 27

복잡도

항목
H_n 직접 계산O(n) 시간, O(1) 공간
Floor sum (구간)O(√n) 시간, O(1) 공간
Σ d(i) (약수 개수 합)O(√n)

변형 / 활용

패턴설명복잡도
Σ ⌊n/i⌋floor sum, O(√n)구간 나누기
Σ i·⌊n/i⌋가중치 곱2중 구간
Σ d(i)약수 개수 합O(√n)
Σ σ(i)약수 합O(√n)
Divisor summatoryD(n) = Σ_{i≤n} ⌊n/i⌋정수론 핵심

함정

1. 부동소수점 정밀도

H_n 은 float/double 로 n ≥ 10^7 이면 오차 누적. 큰 n 에 대해서는 log(n) + γ 근사식 사용.

2. 64-bit 오버플로우

floor_sum(n) 에서 n=10^12 면 q * (r-l+1)long long 초과 가능. unsigned long long 또는 __int128 필요.

3. 구간 경계 실수

l = r + 1 에서 ln+1 이면 루프 종료. r = n / (n / l) 에서 n / l == 0 이면 0으로 나누기 방지: l > n 이면 break.

BOJ 연습 문제

번호제목정답률링크
BOJ 1222홍준 프로그래밍 대회25.6%kokoa-lab
BOJ 2247실질적 약수37.3%kokoa-lab
BOJ 1241머리 톡톡34.6%kokoa-lab
BOJ 2900프로그램-kokoa-lab

참고

이 글의 용어 (3개)
에라토스테네스의 체 (Sieve of Eratosthenes)algorithm
정의 에라토스테네스의 체 (Sieve of Eratosthenes) 는 1부터 N 까지의 모든 소수를 O(N log log N) 에 찾는 고대 그리스 알고리즘. 기원전 240 년…
Inclusion and Exclusion: 포함배제 원리algorithm
정의 $$ \left| \bigcup{i=1}^{n} Ai \right| = \sum \lvert Ai \rvert - \sum \lvert Ai \cap Aj \rvert + …
Mobius Function, Mobius Inversionalgorithm
정의 Mobius Function 은 양의 정수에 대한 수론 함수: Mobius Inversion (뫼비우스 역원) 은 합 / 컨볼루션 관계의 역변환. PS 에서는 GCD / 서…

💬 댓글

사이트 검색 / 명령어

검색

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