※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 27435번 문제인 파도반 수열 2이다.
문제는 아래 링크를 확인하자.

https://www.acmicpc.net/problem/27435 

 

27435번: 파도반 수열 2

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. (1 ≤ T ≤ 1,000, 1 ≤ N ≤ 1018)

www.acmicpc.net

파도반 수열(Padovan sequence)이란 \(P_1=P_2=P_3=1\)이고 \(P_N = P_{N-2} + P_{N-3}\)와 같은 점화식을 만족시키는 수열을 의미한다. (단, 정의에 따라 초기값의 인덱스는 다를 수 있다.)

 

실제로 주어진 그림에서 보조선을 적절히 그으면 위의 점화관계가 성립함을 알 수 있다. 예를 들어, 본문에 주어진 그림에서 "한 변의 길이가 4인 정삼각형와 5인 정삼각형의 맞닿은 변"을 한 변의 길이가 9인 정삼각형과 만날 때까지 연장한 보조선을 긋는다면 위의 점화식이 성립함을 간단히 관찰할 수 있다. (평행사변형을 잘 살펴보자.)

 

위의 점화식은 행렬을 이용해 아래와 같이 표현할 수 있다.

 

\( \begin{pmatrix} 0 & 1 & 1\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} P_n\\ P_{n-1}\\ P_{n-2}\end{pmatrix} = \begin{pmatrix} P_{n+1}\\ P_n\\ P_{n-1}\end{pmatrix}\)

 

위와 같은 식과 적절한 초기값, 그리고 binary exponentiation을 이용해 \(P_N\)의 값을 \(O(lg(N))\)에 구하고 문제를 해결하자.

 

파도반 수열에 대해 더 자세히 알고 싶다면 위키백과(링크) OEIS(링크) 등을 참고하자.

 

아래는 제출한 소스코드이다.

#define MOD 998244353
#include <iostream>
using namespace std;
typedef long long ll;

ll T, N[1000];

ll mat[3][3];
ll mtmp[3][3];
ll vec[1000][3];
ll vtmp[3];

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	mat[0][1] = mat[0][2] = mat[1][0] = mat[2][1] = 1;

	cin >> T;
	for (int t = 0; t < T; t++) cin >> N[t], vec[t][1] = 1;
	
	for (int i = 0; i < 64; i++) {
		for (int t = 0; t < T; t++) {
			if (N[t] & 1) {
				vtmp[0] = mat[0][0] * vec[t][0] + mat[0][1] * vec[t][1] + mat[0][2] * vec[t][2];
				vtmp[1] = mat[1][0] * vec[t][0] + mat[1][1] * vec[t][1] + mat[1][2] * vec[t][2];
				vtmp[2] = mat[2][0] * vec[t][0] + mat[2][1] * vec[t][1] + mat[2][2] * vec[t][2];
				vec[t][0] = vtmp[0] % MOD, vec[t][1] = vtmp[1] % MOD, vec[t][2] = vtmp[2] % MOD;
			}
			N[t] >>= 1;
		}

		for (int r = 0; r < 3; r++) {
			for (int c = 0; c < 3; c++) {
				ll& cur = mtmp[r][c] = 0;
				for (int k = 0; k < 3; k++) {
					cur += mat[r][k] * mat[k][c];
				}
			}
		}
		for (int r = 0; r < 3; r++) {
			for (int c = 0; c < 3; c++) {
				mat[r][c] = mtmp[r][c] % MOD;
			}
		}
	}

	for (int t = 0; t < T; t++) cout << vec[t][0] << '\n';
}
728x90

+ Recent posts