길이 \(n\) (최대 \(10^6\))의 문자열 \(s\)가 A/B로만 주어질 때,
- \(1 \le i < j \le n\)
- \(s[i] = B\), \(s[j] = A\)
- \(j-i = k\)
를 만족하는 쌍을 k-inversion이라 한다.
요구사항은 모든 \(k = 1 \ldots n-1\) 에 대해 k-inversion 개수를 출력하는 것이다.
핵심은 각 \(k\)마다 세는 식 \(\sum_i [s[i]=B]\cdot[s[i+k]=A]\) 을 상관(cross-correlation) 으로 보고, 이를 컨볼루션(convolution) 으로 바꿔 FFT 한 번으로 전부 계산하는 것이다.
문제 정보
문제 링크: https://www.acmicpc.net/problem/13055
문제 요약:
- 길이 \(n\)의 문자열 \(s\) (문자
A,B만 포함)가 주어진다. - 각 \(k = 1..n-1\)에 대해, 거리 \(k\)만큼 떨어진 위치에서
B가 앞,A가 뒤인 쌍 \((i, i+k)\)의 개수를 출력한다.
제한 조건:
- 시간 제한: 10초
- 메모리 제한: 512MB
- \(1 \le n \le 1{,}000{,}000\)
입출력 예제
입력 1:
| |
출력 1:
| |
접근 방식
핵심 관찰: “모든 k에 대한 오프셋 매칭”은 상관(correlation)이다
0-based로 두고,
- \(B[i] = 1\) if \(s[i]='B'\) else 0
- \(A[i] = 1\) if \(s[i]='A'\) else 0
라 하면, 우리가 원하는 값은
\[ ans[k] = \sum_{i=0}^{n-1-k} B[i]\cdot A[i+k] \quad (k=1..n-1) \]이다. 이는 \(B\)와 \(A\)의 cross-correlation 형태라서, 직접 계산하면 \(O(n^2)\)가 된다.
컨볼루션으로 바꾸는 트릭: A를 뒤집어 곱하면 된다
\(A\)를 뒤집은 배열을
\[ Arev[t] = A[n-1-t] \]로 두고, 컨볼루션
\[ C = B * Arev,\quad C[x] = \sum_{i} B[i]\cdot Arev[x-i] \]를 생각하자. 그러면 \(k\)에 대한 답이 컨볼루션의 특정 인덱스에 정확히 대응한다.
- \(Arev[x-i] = A[n-1-(x-i)]\)
- 우리가 원하는 \(A[i+k]\)가 되려면 \(n-1-(x-i) = i+k\)
- 즉 \(x = (n-1) - k\)
따라서
\[ ans[k] = C[(n-1)-k] \]가 된다. 이제 FFT로 \(C\)를 한 번만 계산하면 모든 \(k\) 답을 바로 출력할 수 있다.
알고리즘 설계 (Mermaid Flowchart)
flowchart TD
S["입력: 문자열 s (길이 n)"] --> M1["배열 B[i]=1(s[i]=='B'), A[i]=1(s[i]=='A') 생성"]
M1 --> M2["Arev[t] = A[n-1-t]로 뒤집기"]
M2 --> M3["FFT 길이 N: N >= 2n인 2의 거듭제곱 선택"]
M3 --> M4["B, Arev를 길이 N으로 패딩 후 FFT"]
M4 --> M5["주파수 도메인에서 점별 곱"]
M5 --> M6["IFFT로 컨볼루션 C 복원"]
M6 --> M7["k=1..n-1에 대해 ans[k]=round(C[n-1-k]) 출력"]
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | \(O(n \log n)\) | FFT 2회 + IFFT 1회 |
| 공간 복잡도 | \(O(n)\) | 길이 \(N(\approx 2n)\) 복소 배열 사용 |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| n=1 | 출력 라인이 없음 | 바로 종료(아무 것도 출력하지 않음) |
| 모든 문자가 A 또는 B | 답이 전부 0일 수 있음 | 인디케이터 배열로 자동 처리 |
| 부동소수점 오차 | FFT 결과가 정수가 아니게 나올 수 있음 | llround(real)로 반올림 |
| 대용량 출력 | 최대 \(n-1\) 줄(≈1e6) | string 버퍼에 모아 출력 |
구현 코드 (C++)
| |
![Featured image of post [Algorithm] C++ 백준 13055번: K-Inversions](/post/algorithm/2026-01-30-boj-13055-k-inversions-fft-convolution-cpp-solution/wordcloud_hu_1ba4e422ffadcb1.png)
![[Algorithm] C++ 백준 12925번: Numbers](/post/algorithm/2026-01-30-boj-12925-numbers-matrix-exponentiation-cpp-solution/wordcloud_hu_3ddd9b1682d67718.png)
![[Algorithm] C++ 백준 13055번: K-Inversions](/post/algorithm/2026-01-30-boj-13055-k-inversions-fft-convolution-cpp-solution/wordcloud_hu_7e5ebc7c87d06324.png)
![[Algorithm] C++ 백준 15517번: Array Manipulation at Moloco (Hard)](/post/algorithm/2026-01-30-boj-15517-array-manipulation-at-moloco-hard-fenwick-cpp-solution/wordcloud_hu_521deba1ba8bdbdd.png)
![[Algorithm] C++ 백준 14288번: 회사 문화 4](/post/algorithm/2026-01-24-boj-14288-company-culture-4-tree-queries-fenwick-cpp-solution/wordcloud_hu_71f27d76781ea5f9.png)
![[Algorithm] C++ 백준 24271번: xor²](/post/algorithm/2026-01-24-boj-24271-xor-squared-xor-permutation-segment-tree-cpp-solution/wordcloud_hu_26a096bd3c9cd391.png)
![[Algorithm] C++ 백준 20176번: Needle](/post/algorithm/2025-12-19-boj-20176-needle-cpp-solution/wordcloud_hu_a3ed51dd964546bf.png)
![[Algorithm] C++ 백준 15576번: 큰 수 곱셈 (2)](/post/algorithm/2025-09-16-boj-15576-big-integer-multiplication-2-cpp-solution/wordcloud_hu_8fa6beeb7ce92fde.png)
![[Algorithm] C++ 백준 9120번: Oulipo 다국어](/post/algorithm/2026-01-05-boj-9120-oulipo-multilingual-kmp-string-matching-cpp-solution/wordcloud_hu_801cf29e8e8a768d.png)
![[Algorithm] C++ 백준 2586번: 소방차](/post/algorithm/2025-12-19-boj-2586-firetruck-cpp-solution/wordcloud_hu_c602f70948ace931.png)