티스토리 뷰
Bostan Mori 알고리즘은 2020년 8월 Alin Bostan과 Ryuhei Mori가 작성한 이 논문에 소개되어 있는 선형점화식을 가지는 수열의 $N$ 번째 항을 빠르게 구하는 알고리즘이다. Bostan Mori 알고리즘 이외에 선형점화식을 가지는 수열의 $N$ 번째 항을 빠르게 구하는 방법은 이 글을 참고하자.
$D_0, D_1, \cdots, D_{k-1}$과 $c_1, c_2, \cdots, c_k$가 주어졌을 때, $i \ge k$인 $D_i$를 다음과 같은 선형점화식으로 구할 수 있다고 하자.
$$D_i = \sum_{j=1}^{k}{c_jD_{i-j}} = c_1D_{i-1} + c_2D_{i-2} + \cdots + c_kD_{i-k}$$
이러한 선형점화식이 주어졌을 때, $D_N$을 Bostan Mori 알고리즘을 통해 구하는 방법을 알아보자.
$D$의 각 원소를 계수로 가지는 생성함수 $F$와 점화식을 바탕으로 만들어진 다항함수 $Q$가 있다.
$$F(x) = \sum_{n=0}^{\infty}{D_nx^n}\\Q(x) = 1-c_1x-c_2x^2-\cdots-c_kx^k$$
여기서, $F(x) = \frac{P(x)}{Q(x)}$를 만족하는 다항함수 $P$가 존재한다는 것과 $P$의 차수가 $k$ 보다 작다는 것을 보일 수 있다. $P(x) = F(x)Q(x)$이고, $i \ge k$인 $i$에 대해 $P(x)$의 $x^i$ 항의 계수를 구해보면 $D_i - c_1D_{i-1} - c_2D_{i-2} - \cdots - c_kD_{i-k} = 0$이다. 즉, $P(x)$의 차수는 $k$ 보다 작다.
구하고자 하는 것은 $N$ 번째 항인 $D_N$이다. 이는 $F(x) = \frac{P(x)}{Q(x)}$의 $x^N$ 항의 계수이다. 이를 다음과 같은 수식으로 표현하자.
$$\left[x^N\right]\frac{P(x)}{Q(x)}$$
위 분수의 분자와 분모 모두에 $Q(-x)$를 곱해보자. 즉, $\frac{P(x)}{Q(x)} = \frac{P(x)Q(-x)}{Q(x)Q(-x)}$이다.
이때, $Q(x)$의 차수는 $k$이다. $Q(x)Q(-x)$는 짝함수이기 때문에 $V(x^2)$으로 나타낼 수 있으며 $V$의 차수는 $k$ 이하다. $P(x)Q(-x) = U(x)$로 쓰자. $P(x)$의 차수는 $k$ 보다 작기 때문에 $U(x)$의 차수는 $2k$ 보다 작다. $U(x)$를 홀수차항과 짝수차항으로 $U(x) = U_e(x^2) + xU_o(x^2)$처럼 나누자. 여기서 $U_e(x)$와 $U_o(x)$의 차수는 $k$ 보다 작다. 이를 통해 식을 다음처럼 정리할 수 있다.
$$\frac{P(x)}{Q(x)} = \frac{P(x)Q(-x)}{Q(x)Q(-x)} = \frac{U_e(x^2)}{V(x^2)} + x\frac{U_o(x^2)}{V(x^2)}$$
유리함수 $P/Q$의 $x^N$ 항의 계수는 다음과 같이 정리된다.
$$\left[ x^N \right]\frac{P(x)}{Q(x)} = \begin{cases}
\left[ x^{\frac{N}{2}} \right] \frac{U_e(x)}{V(x)}, & \text{if $N$ is even,}\\
\left[ x^{\frac{N-1}{2}} \right] \frac{U_o(x)}{V(x)}, & \text{otherwise}
\end{cases}$$
즉, 분자의 차수가 $k$보다 작고, 분모의 차수가 $k$ 이하인 유리함수 $P/Q$의 $x^N$ 항의 계수를 구하기 위해 같은 조건을 가지고 있는 또다른 유리함수의 $x^{\lfloor N/2 \rfloor}$의 계수를 구하도록 차원을 줄였다. 이처럼 두 번의 다항식 곱셈으로 구하고자 하는 항의 차수를 반으로 줄일 수 있다. 이를 상수항의 계수를 구할 때까지 반복한다. 유리함수 $P/Q$의 상수 계수는 $P(0)/Q(0)$으로 바로 구할 수 있다.
일반적인 방법으로 다항식의 곱셈을 구현하면 $O(k^2)$ 시간복잡도가 되고, FFT나 NTT를 통해 다항식의 곱셈을 구현하면 $O(k \lg k)$ 시간복잡도가 된다. 따라서, 전체 시간복잡도는 $O(k^2 \lg N)$ 혹은 $O(k \lg k \lg N)$이다.
연습 문제
문제의 MOD 값이 1999이므로 NTT를 사용할 수 없다. $k$의 최댓값이 1000으로 크지 않으므로 $O(k^2 \lg N)$ 시간복잡도로 해결할 수 있다.
MOD 값이 $104857601 = 25 \times 2^{22}+1$ 로 NTT를 쓸 수 있다. 원시근은 2부터 차례대로 구해보면 되는데, 3이 원시근이 된다. $k$의 최댓값이 30000으로 크기 때문에 $O(k \lg k \lg N)$ 시간복잡도로 문제를 해결해야 한다.
아래 코드는 BOJ 13725 RNG 문제를 해결하는 코드이며, mod int와 NTT를 이용한 다항식 템플릿을 포함한 코드다.
'공부' 카테고리의 다른 글
선형점화식 빠르게 계산하기 (0) | 2022.11.30 |
---|---|
다항식 나눗셈의 몫을 빠르게 구하는 방법 (1) | 2022.11.29 |
Hu-Tucker Algorithm (0) | 2022.05.03 |
Skew Heap (0) | 2022.05.03 |
Z-function (2) | 2021.03.08 |
- Total
- Today
- Yesterday
- HackerRank
- moore
- Greedy Method
- IOI2012
- Tree
- IOI2013
- TRIE
- Splay Tree
- IOI2014
- idea
- Parametric Search
- vote
- BOI 2001
- Segment tree
- IOI2011
- BOI 2009
- optimization
- BOI
- Boyer
- USACO
- Dynamic Pramming
- majority
- Boyer-Moore Majority Vote Algorithm
- dynamic programming
- Divide & Conquer
- z-trening
- Dijkstra
- Algorithm
- ioi
- Knuth Optimization
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |