무엇을 가속하나
피보나치 \(f_n = f_{n-1} + f_{n-2}\) 같은 선형 점화식의 \(N\)번째 항을 단순
반복으로 구하면 \(O(N)\)이 든다. \(N\)이 \(10^{18}\)처럼 크면 불가능하다. 행렬
거듭제곱은 이를 \(O(K^3 \log N)\)으로 줄인다(\(K\)는 점화식의 차수).
점화식을 행렬로 옮기기
상태 벡터를 점화식이 참조하는 최근 항들로 잡는다. 피보나치라면
\(\begin{pmatrix} f_n \\ f_{n-1} \end{pmatrix}\)를 한 단계 진행시키는 변환은
$$ \begin{pmatrix} f_{n+1} \\ f_n \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} \begin{pmatrix} f_n \\ f_{n-1} \end{pmatrix} $$
이다. 이 변환 행렬을 \(A\)라 하면, 초기 벡터에 \(A\)를 \(n\)번 곱한 것이 답이다.
즉 \(\begin{pmatrix} f_{n+1} \\ f_n \end{pmatrix} = A^n \begin{pmatrix} f_1 \\ f_0 \end{pmatrix}\).
일반화: \(f_n = c_1 f_{n-1} + \dots + c_k f_{n-k}\)이면 변환 행렬은 첫 행이
\((c_1, \dots, c_k)\)이고 그 아래에 항등 부분 행렬을 둔 동반 행렬이다.
거듭제곱을 빠르게: 분할 정복
행렬 거듭제곱 \(A^n\)은 정수 거듭제곱과 똑같이 분할 정복(이진 거듭제곱) 으로
계산한다.
$$ A^n = \begin{cases} (A^{n/2})^2 & n \text{ 짝수} \\ A \cdot A^{n-1} & n \text{ 홀수} \end{cases} $$
곱셈 횟수가 \(O(\log N)\)번이고, 한 번의 \(K \times K\) 행렬 곱이 \(O(K^3)\)이므로
전체 \(O(K^3 \log N)\)이다.
왜 옳은가
행렬 곱은 결합법칙을 만족하므로, \(A\)를 \(n\)번 곱하는 것은 어떤 순서로 묶어
곱해도 결과가 같다. 따라서 지수를 절반씩 나누는 분할 정복이 그대로 성립한다.
이는 정수 빠른 거듭제곱이 옳은 이유와 정확히 같은 원리다.
적용 범위
선형 점화식뿐 아니라 그래프에서 길이 \(L\) 경로의 수(인접 행렬의 \(L\)제곱),
상태 전이가 일정한 동적 계획법, 타일링·문자열 카운팅 등 "같은 선형
변환을 여러 번 반복"하는 모든 문제에 쓸 수 있다. 답이 크면 보통 모듈러
\(10^9 + 7\)로 계산한다.