https://www.acmicpc.net/problem/27435
27435번: 파도반 수열 2
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. (1 ≤ T ≤ 1,000, 1 ≤ N ≤ 1018)
www.acmicpc.net
파도반 수열의 초반 항이 10개 주어져있고, 그림도 친절하게 주어져있어 점화식을 추론하기 쉽습니다.
$$P(n) = P(n-1) + P(n-5)$$
이 점화식에 따르면 $5 \times 5$ 행렬 거듭제곱을 통해 빠르게 답을 구할 수 있게 됩니다.
$$ \begin{bmatrix} P(n+4) \\ P(n+3) \\ P(n+2) \\ P(n+1) \\ P(n) \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \end{bmatrix}^{n} \begin{bmatrix} P(4) \\ P(3) \\ P(2) \\ P(1) \\ P(0) \end{bmatrix} $$
주어진 점화식과 주어진 초반 10개 항의 값에 따라 $P(0)=0$으로 놓을 수 있어 답이 결정됩니다.
그러나, 파도반 수열은 점화식이 하나 더 있습니다.
$$P(n) = P(n-2) + P(n-3)$$
이 식을 쓰면 $3 \times 3$ 행렬 거듭제곱을 통해 답을 구할 수 있으므로 상수 커팅의 효과가 있겠습니다.
제 코드는 다음과 같습니다.
#include <stdio.h>
#define mod 998244353
typedef struct {
unsigned long long array[3][3];
} Matrix;
Matrix matrix_multiply_modular (Matrix A, Matrix B);
Matrix matrix_power_modular (Matrix A, long long P);
Matrix Base =
{{
{0, 1, 1},
{1, 0, 0},
{0, 1, 0}
}};
int main(void) {
int T;
scanf("%d", &T);
while(T--) {
long long N;
scanf("%lld", &N);
if (N <= 3) {
printf("1\n");
continue;
}
Matrix Answer = matrix_power_modular(Base, N - 3);
printf("%llu\n", (Answer.array[0][0] + Answer.array[0][1] + Answer.array[0][2]) % mod);
}
return 0;
}
Matrix matrix_multiply_modular (Matrix A, Matrix B) {
Matrix result = {{{}}};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
result.array[i][j] += A.array[i][k] * B.array[k][j];
}
result.array[i][j] %= mod;
}
}
return result;
}
Matrix matrix_power_modular (Matrix A, long long P) {
Matrix result = {{{}}};
for (int i = 0; i < 3; i++) {
result.array[i][i] = 1;
}
while(P) {
if (P % 2) {
result = matrix_multiply_modular (result, A);
}
A = matrix_multiply_modular (A, A);
P /= 2;
}
return result;
}
(C11, 4ms, 1116KB, 제출번호 56631974)
단순한 코드인데, 0ms를 찍는 게 힘들어 포기했습니다.. 0ms을 기록하신 분의 코드는 읽어봤는데 아마 Padovan Sequence를 생성하는 matrix를 기반으로 한 것 같긴 합니다. 전반적인 알고리즘은 같은 듯한데, 0ms가 나온 건 함수의 inline화가 큰 영향이 있는 듯 하구요...
참고) 링크에 따르면, Fibonacci Sequence처럼 Padovan Sequence에서도 다음이 성립한다고 합니다.
$$\begin{bmatrix} 0 & 1 & 0 \\ 0 & 0 & 1 \\ 1 & 1 & 0 \end{bmatrix}^{n} = \begin{bmatrix} P(n-5) & P(n-3) & P(n-4) \\ P(n-4) & P(n-2) & P(n-3) \\ P(n-3) & P(n-1) & P(n-2) \end{bmatrix}$$
'분할 정복을 이용한 거듭제곱 > 행렬 거듭제곱' 카테고리의 다른 글
백준 27318번: 세상에서 가장 달달한 디저트 만들기 (matrix) (0) | 2023.03.11 |
---|---|
백준 9819번: Color Change of Go Game Pieces (0) | 2023.03.03 |
백준 17315번: Matrix Game (matrix interpretation) (0) | 2023.02.03 |
백준 14553번: The Way (0) | 2023.01.17 |
백준 13380번: Found (0) | 2023.01.16 |