문제의 핵심은 각 소 i에 대해 왼쪽/오른쪽에 있는 ‘자기보다 키 큰 소’의 개수(Li, Ri) 를 빠르게 세고, \(\max(L_i, R_i) > 2 \cdot \min(L_i, R_i)\) 인 소의 수를 구하는 것입니다.
문제 정보
문제 링크: https://www.acmicpc.net/problem/14449
문제 요약:
서로 다른 키를 가진 N마리의 소가 한 줄에 서 있다. 각 소 i에 대해 왼쪽과 오른쪽에 있는 ‘i보다 키 큰 소’의 수를 각각 \(L_i\), \(R_i\)라 할 때, 큰 쪽이 작은 쪽의 2배를 초과하면(엄밀히 \(\max(L_i,R_i) > 2\min(L_i,R_i)\)) i는 unbalanced이다. 전체 unbalanced 소의 수를 출력한다.
제한 조건:
- 시간 제한: 2초
- 메모리 제한: 512MB
- 입력 크기: \(1 \le N \le 100{,}000\)
- 키 \(h_i\): 서로 모두 다르며 \(0 \le h_i \le 1{,}000{,}000{,}000\)
입출력 예제
입력 1:
| |
출력 1:
| |
접근 방식
핵심 관찰
- 각 소 i에 대해 필요한 정보는 \(L_i\)와 \(R_i\) 뿐이다.
- \(L_i\)는 “i의 왼쪽 구간에서 i보다 큰 값의 개수”이므로, 왼쪽에서 오른쪽으로 스캔하면서 현재까지 등장한 키들의 빈도로 계산할 수 있다.
- 키 값은 최대 1e9이므로 그대로 인덱싱할 수 없고, 좌표압축 후 펜윅트리(Fenwick Tree / BIT)로 빈도 누적합을 관리하면 \(O(\log N)\)에 질의/갱신이 가능하다.
알고리즘 설계 (Mermaid Flowchart)
flowchart TD
A["입력: N, h[0..N-1]"] --> B["좌표압축: 키를 1..M으로 매핑"]
B --> C["왼쪽->오른쪽 스캔: L[i] 계산 (BIT)"]
C --> D["오른쪽->왼쪽 스캔: R[i] 계산 (BIT)"]
D --> E["각 i에 대해 조건 검사: max(L,R) > 2*min(L,R)"]
E --> F["unbalanced 개수 출력"]
단계별 로직
좌표압축
- 모든 키를 정렬해 1..M(=N) 범위의 인덱스로 치환한다.
왼쪽 큰 소 개수 \(L_i\)
- i를 0..N-1로 증가시키며 BIT에 지금까지 나온 키를 1개씩 추가한다.
- 현재 키의 압축 인덱스를 idx라 하면
- 현재까지 처리한 개수 = i
- 현재까지 \(\le h_i\) 개수 =
sum(idx) - 따라서 \(L_i = i - sum(idx)\) (자기보다 큰 것만 카운트)
오른쪽 큰 소 개수 \(R_i\)
- i를 N-1..0으로 감소시키며 똑같이 계산한다.
정답 집계
- 각 i에 대해
mx = max(L[i], R[i]),mn = min(L[i], R[i])라 하면 mx > 2*mn인 경우만 센다.
- 각 i에 대해
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | \(O(N \log N)\) | 좌표압축 정렬 \(N\log N\) + BIT 스캔 2회 \(2N\log N\) |
| 공간 복잡도 | \(O(N)\) | 입력/압축배열 + BIT + L/R 배열 |
구현 코드
C++
| |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| \(N = 1\) | 좌/우가 모두 0 | \(\max=0\)이므로 unbalanced 아님 |
| 한쪽만 큰 소가 존재 | 예: (L=0, R>0) | mx > 2*mn에서 mn=0이면 R>0일 때 항상 참이므로 그대로 카운트해야 함 |
| 오버플로우 | 2*mn 계산 | mn은 최대 N이므로 long long로 비교하면 안전 |
| 좌표압축 인덱스 | BIT는 1-based | +1 오프셋을 빼먹지 않기 |
![Featured image of post [Algorithm] C++ 백준 14449번: Balanced Photo](/post/algorithm/2025-12-15-boj-14449-balanced-photo-cpp-solution/wordcloud_hu_93bf61ef80a3e757.png)
![[Algorithm] C++ 백준 14449번: Balanced Photo](/post/algorithm/2025-12-15-boj-14449-balanced-photo-cpp-solution/wordcloud_hu_c3927a1977c9e917.png)
![[Algorithm] C++ 백준 27046번: Beauty Contest](/post/algorithm/2025-12-15-boj-27046-beauty-contest-cpp-solution/wordcloud_hu_36b430743b631c29.png)
![[Algorithm] C++ 백준 13618번: RSA](/post/algorithm/2025-12-12-boj-13618-rsa-cpp-solution/wordcloud_hu_ef9169c0740863be.png)
![[Algorithm] C++ 백준 30853번: Black Box](/post/algorithm/2025-12-12-boj-30853-black-box-cpp-solution/wordcloud_hu_87d0c2f42c088d65.png)
![[Algorithm] C++ 백준 31222번 : 수열과 어렵지 않은 쿼리](/post/algorithm/2025-12-12-boj-31222-sequence-and-not-so-hard-queries-cpp-solution/wordcloud_hu_6068bcd736ddbb4b.png)
![[Algorithm] C++ 백준 13537번: 수열과 쿼리 1 - 오프라인 BIT](/post/algorithm/2025-08-14-boj-13537-sequence-and-queries-1-offline-bit-cpp-solution/wordcloud_hu_cbc1305f194d9d9e.png)
![[Algorithm] C++ 백준 11012번: Egg - 2D 직사각형 쿼리 스위핑+BIT](/post/algorithm/2025-08-14-boj-11012-egg-cpp-solution/wordcloud_hu_ff8aab4a98180994.png)
![[Algorithm] C++ 백준 5920번: Cow Photography](/post/algorithm/2025-12-11-boj-5920-cow-photography-cpp-solution/wordcloud_hu_ab327ea8ee254ac3.png)
![[Algorithm] C++ 백준 13545번: 수열과 쿼리 0](/post/algorithm/2025-08-14-boj-13545-sequence-and-queries-0-cpp-solution/wordcloud_hu_6fd0a9d61a05ee45.png)
![[Algorithm] C++ 백준 5466번: 상인](/post/algorithm/2025-08-14-boj-5466-merchant-cpp-solution/wordcloud_hu_2a64d059bc995c5d.png)