이 문제는 **엄격 증가 수열 \(B\)**를 하나 출력하되, \(\sum |B_i-A_i|\)를 최소화해야 한다.
핵심은 \(B_i < B_{i+1}\) 제약을 \(A_i-i\)로 치환해 **비내림 수열에 대한 L1 최소화(아이소토닉 회귀)**로 바꾸는 것이다.
문제 정보
문제 요약:
- 정수 수열 \(A_1,\dots,A_N\)이 주어진다.
- \(B_1 < B_2 < \dots < B_N\)을 만족하는 정수 수열 \(B\) 중에서 \[ \sum_{i=1}^{N} |B_i - A_i| \] 값을 최소화하는 \(B\)를 아무거나 출력한다.
- 출력하는 \(B_i\)는 모두 32비트 signed int 범위 안이어야 한다. (스페셜 저지)
제한 조건:
- 시간 제한: 2초
- 메모리 제한: 512MB
- \(N \le 1{,}000{,}000\)
- \(0 \le A_i \le 2 \times 10^9\)
입출력 예제
예제 입력 1:
| |
예제 출력 1:
| |
접근 방식
핵심 변환: 엄격 증가 \(\rightarrow\) 비내림
\(C_i = B_i - i\)로 두면,
- \(B_i < B_{i+1}\)
\(\Leftrightarrow C_i + i < C_{i+1} + (i+1)\)
\(\Leftrightarrow C_i \le C_{i+1}\)
즉, \(C\)는 비내림 수열이면 된다.
또한 목적함수는
\[ \sum_{i=1}^{N} |B_i-A_i| = \sum_{i=1}^{N} |(C_i+i)-A_i| = \sum_{i=1}^{N} |C_i - (A_i-i)| \]따라서 \(D_i = A_i - i\)에 대해 **비내림 수열 \(C\)**를 하나 골라 \(\sum |C_i-D_i|\)를 최소화하면 된다.
핵심 아이디어: prefix 중앙값을 힙으로 유지
L1 비용에서 “상수로 맞출 때의 최적 값”은 **중앙값(median)**이다.
비내림 제약이 걸리면 최적해는 “구간별 상수(block)” 형태가 되며, 각 블록 값은 해당 구간 \(D\)들의 중앙값으로 잡을 수 있다.
이를 구현하는 유명한 트릭이 다음이다:
- 최대 힙
pq에 매 단계 \(D_i\)를 두 번 push하고 한 번 pop하여pq.top()이 현재까지의 “선택된 중앙값” 역할을 하도록 만든다. - 이렇게 얻은 임시값 배열
C[i]는 뒤에서 앞으로 한 번 더 훑어C[i] = min(C[i], C[i+1])로 비내림 조건을 강제한다.
알고리즘 설계 (Mermaid Flowchart)
flowchart TD
A["입력 N, A[1..N]"] --> B["D[i] = A[i] - i 계산"]
B --> C["최대 힙 pq 초기화"]
C --> D["i=1..N 반복:pq에 D[i] 2번 push1번 popC[i]=pq.top()"]
D --> E["역방향 보정:for i=N-1..1C[i]=min(C[i], C[i+1])"]
E --> F["출력:B[i]=C[i]+i 를 N줄 출력"]
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | \(O(N \log N)\) | 각 원소당 힙 연산 상수 번 |
| 공간 복잡도 | \(O(N)\) | C 배열 저장(출력을 위해 필요) |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 |
|---|---|---|
| N이 매우 큼 (1e6) | I/O 및 힙 연산이 병목 | ios::sync_with_stdio(false), cin.tie(nullptr) |
| A가 큼 (2e9) | A-i도 큼 | long long 사용 |
| 출력 범위(32-bit) | 문제에서 요구 | 이 풀이로 나오는 최적해는 조건을 만족하도록 존재한다고 가정(문제 조건) |
| 엄격 증가 vs 비내림 | 변환에서 자주 실수 | \(C_i = B_i-i\)로 바꾸면 비내림이 된다 |
구현 코드
C++
| |
![Featured image of post [Algorithm] C++ 백준 13324번: BOJ 수열 2](/post/algorithm/2025-12-19-boj-13324-boj-sequence-2-cpp-solution/wordcloud_hu_b9db8580ab824509.png)
![[Algorithm] C++ 백준 3752번: 최대공약수 행렬식](/post/algorithm/2025-12-20-boj-3752-gcd-matrix-determinant-cpp-solution/wordcloud_hu_1490cf2b4f293afc.png)
![[Algorithm] C++ 백준 1185번: 유럽여행](/post/algorithm/2025-12-19-boj-1185-europe-travel-mst-kruskal-cpp-solution/wordcloud_hu_a7973902548ef27b.png)
![[Algorithm] C++ 백준 13324번: BOJ 수열 2](/post/algorithm/2025-12-19-boj-13324-boj-sequence-2-cpp-solution/wordcloud_hu_5564e49074c47ebd.png)
![[Algorithm] C++ 백준 13539번: 트리와 쿼리 11](/post/algorithm/2025-12-19-boj-13539-tree-and-query-11-link-cut-tree-cpp-solution/wordcloud_hu_22549d9781144aba.png)
![[Algorithm] C++ 백준 14853번: 동전 던지기](/post/algorithm/2025-12-19-boj-14853-coin-tossing-cpp-solution/wordcloud_hu_38e38de527bab2db.png)
![[Algorithm] C++ 백준 13323번: BOJ 수열 1 - Slope Trick](/post/algorithm/2025-08-14-boj-13323-boj-sequence-1-slope-trick-pq-cpp-solution/wordcloud_hu_7b65bcc13669e74c.png)
![[Algorithm] C++ 백준 1777번: 순열복원](/post/algorithm/2025-12-19-boj-1777-permutation-recovery-cpp-solution/wordcloud_hu_e783e8b2198c2957.png)
![[Algorithm] C++ 백준 32190번: Ian Sequences](/post/algorithm/2025-12-19-boj-32190-ian-sequences-cpp-solution/wordcloud_hu_266416599cd1461b.png)
![[Algorithm] C++ 백준 3006번: 터보소트](/post/algorithm/2025-12-19-boj-3006-turbosort-cpp-solution/wordcloud_hu_cd4b400156e60fdb.png)