본문 바로가기

분할 정복을 이용한 거듭제곱/행렬 거듭제곱

백준 18287번: 체스판 이동

www.acmicpc.net/problem/18287

 

18287번: 체스판 이동

크기가 N×M인 체스판이 있다. 체스판의 행 번호는 위에서부터 1, 2, ..., N이고, 열 번호는 왼쪽에서부터 1, 2, ..., M이다. 체스판의 각 칸은 (i, j)로 표현하고, i는 행 번호, j는 열 번호이다. 체스판의

www.acmicpc.net


우선 체스판이 어떻게 생겼는지 알아야 합니다.

 

검정색 칸을 $B$, 흰색 칸을 $W$라고 표현할 때 체스판의 생김새는 다음과 같습니다.

 

$\begin{matrix}B & W & B & W & \cdots\\ W & B & W & B & \cdots\\ \vdots & \vdots & \vdots & \vdots & \ddots\end{matrix}$

 

$M$을 적당히 큰 수라고 생각해보면,

 

$N$번 행에 도착하는 방법은 다음의 합이 됩니다.

 

$\left ( N,1 \right )$에 도착하는 방법

$\left ( N,2 \right )$에 도착하는 방법

$\vdots$

$\left ( N,M \right )$에 도착하는 방법

 

이제 $\left ( i,j \right )$에 도착하는 방법을 $R\left ( i,j \right )$ 라고 해봅시다.

 

가장 먼저 $N$이 짝수일 때, $R\left ( N+1,1 \right )$ 을 구해보겠습니다.

 

이동은 항상 행 번호가 증가하는 쪽으로만 할 수 있습니다.

 

즉, 수직 아래, 왼쪽 아래 대각선, 오른쪽 아래 대각선 세 방향으로만 이동할 수 있다는 뜻입니다.

 

$N$이 짝수인 경우를 계산 중이므로, $\left ( N+1,1 \right )$ 으로 이동할 수 있는 칸은

 

$\left ( N,1 \right )$

$\left ( N,2 \right )$

 

두 칸이 됩니다.

 

같은 이유로 $\left ( N+1,2 \right )$ 으로 이동할 수 있는 칸은 $\left ( N,1 \right )$, $\left ( N,2 \right )$, $\left ( N,3 \right )$ 입니다.

 

결과적으로 다음을 얻을 수 있습니다.

 

$R\left ( N+1,j \right )=\left\{\begin{matrix}R\left ( N,1 \right )+R\left ( N,2 \right ) & j=1\\R\left ( N,j-1 \right )+R\left ( N,j \right )+R\left ( N,j+1 \right ) & 2\leq j< M\\ R\left ( N,M-1 \right )+R\left ( N,M \right ) & j=M\end{matrix}\right.$

 

(단, $N$ 은 짝수)

 

 

이제 $N$이 홀수일 때도 같은 과정을 거치면 다시 다음을 얻습니다.

 

$R\left ( N+1,j \right )=\left\{\begin{matrix}R\left ( N,2 \right ) & j=1\\R\left ( N,j-1 \right )+R\left ( N,j+1 \right ) & 2\leq j< M\\R\left ( N,M \right ) & j=M\end{matrix}\right.$

 

(단, $N$은 홀수)

 

 

$N$이 짝수인지, 홀수인지에 따라 점화식의 형태가 변했습니다.

 

이때 짝수와 홀수 둘을 아우르는 점화식을 발견하려고 할 수도 있겠지만,

 

저의 경우 그냥 각각의 행렬 점화식을 구하여 끝냈습니다.

 

먼저 $N$이 짝수일 경우,

 

$\begin{bmatrix}R\left(N+1,1 \right)\\ R\left(N+1,2 \right)\\ R\left(N+1,3 \right)\\ \vdots\\R\left(N+1,M-2 \right)\\ R\left(N+1,M-1 \right)\\ R\left(N+1,M \right)\end{bmatrix}=\begin{bmatrix}1 & 1 & 0 & 0 & \cdots & 0 & 0 & 0 & 0\\ 1 & 1 & 1 & 0 & \cdots & 0 & 0 & 0 & 0\\ 0 & 1 & 1 & 1 & \cdots & 0 & 0 & 0 & 0\\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots & \vdots\\ 0 & 0 & 0 & 0 & \cdots & 1 & 1 & 1 & 0\\ 0 & 0 & 0 & 0 & \cdots & 0 & 1 & 1 & 1\\ 0 & 0 & 0 & 0 & \cdots & 0 & 0 & 1 & 1\end{bmatrix}\begin{bmatrix}R\left(N,1 \right)\\ R\left(N,2 \right)\\ R\left(N,3 \right)\\ \vdots\\ R\left(N,M-2 \right)\\ R\left(N,M-1 \right)\\ R\left(N,M \right)\end{bmatrix}$

 

 

그리고 $N$이 홀수일 경우,

 

$\begin{bmatrix}R\left(N+1,1 \right)\\ R\left(N+1,2 \right)\\ R\left(N+1,3 \right)\\ \vdots\\R\left(N+1,M-2 \right)\\ R\left(N+1,M-1 \right)\\ R\left(N+1,M \right)\end{bmatrix}=\begin{bmatrix}0 & 1 & 0 & 0 & \cdots & 0 & 0 & 0 & 0\\ 1 & 0 & 1 & 0 & \cdots & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 1 & \cdots & 0 & 0 & 0 & 0\\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots & \vdots\\ 0 & 0 & 0 & 0 & \cdots & 1 & 0 & 1 & 0\\ 0 & 0 & 0 & 0 & \cdots & 0 & 1 & 0 & 1\\ 0 & 0 & 0 & 0 & \cdots & 0 & 0 & 1 & 0\end{bmatrix}\begin{bmatrix}R\left(N,1 \right)\\ R\left(N,2 \right)\\ R\left(N,3 \right)\\ \vdots\\ R\left(N,M-2 \right)\\ R\left(N,M-1 \right)\\ R\left(N,M \right)\end{bmatrix}$

 

 

이렇게 점화식을 얻을 수 있습니다.

 

두 식을 편의상 다음과 같이 나타내겠습니다.

 

$N$이 짝수일 때,

 

$\begin{bmatrix}R\left(N+1,1 \right)\\ R\left(N+1,2 \right)\\ R\left(N+1,3 \right)\\ \vdots\\R\left(N+1,M-2 \right)\\ R\left(N+1,M-1 \right)\\ R\left(N+1,M \right)\end{bmatrix}=\begin{bmatrix} BASE_{1}\end{bmatrix}\begin{bmatrix}R\left(N,1 \right)\\ R\left(N,2 \right)\\ R\left(N,3 \right)\\ \vdots\\ R\left(N,M-2 \right)\\ R\left(N,M-1 \right)\\ R\left(N,M \right)\end{bmatrix}$

 

그리고 $N$이 홀수일 때,

 

$\begin{bmatrix}R\left(N+1,1 \right)\\ R\left(N+1,2 \right)\\ R\left(N+1,3 \right)\\ \vdots\\R\left(N+1,M-2 \right)\\ R\left(N+1,M-1 \right)\\ R\left(N+1,M \right)\end{bmatrix}=\begin{bmatrix} BASE_{2}\end{bmatrix}\begin{bmatrix}R\left(N,1 \right)\\ R\left(N,2 \right)\\ R\left(N,3 \right)\\ \vdots\\ R\left(N,M-2 \right)\\ R\left(N,M-1 \right)\\ R\left(N,M \right)\end{bmatrix}$

 

 

최종적으로 다음을 구현하면 됩니다.

 

$\begin{bmatrix}R\left(2k+1,1 \right)\\ R\left(2k+1,2 \right)\\ R\left(2k+1,3 \right)\\ \vdots\\R\left(2k+1,M-2 \right)\\ R\left(2k+1,M-1 \right)\\ R\left(2k+1,M \right)\end{bmatrix}=\begin{bmatrix} BASE_{1}\end{bmatrix}^{K}\begin{bmatrix}BASE_{2} \end{bmatrix}^{K}\begin{bmatrix}R\left(1,1 \right)\\ R\left(1,2 \right)\\ R\left(1,3 \right)\\ \vdots\\ R\left(1,M-2 \right)\\ R\left(1,M-1 \right)\\ R\left(1,M \right)\end{bmatrix}$

 

 

$\begin{bmatrix}R\left(2k,1 \right)\\ R\left(2k,2 \right)\\ R\left(2k,3 \right)\\ \vdots\\R\left(2k,M-2 \right)\\ R\left(2k,M-1 \right)\\ R\left(2k,M \right)\end{bmatrix}=\begin{bmatrix} BASE_{1}\end{bmatrix}^{K-1}\begin{bmatrix}BASE_{2} \end{bmatrix}^{K}\begin{bmatrix}R\left(1,1 \right)\\ R\left(1,2 \right)\\ R\left(1,3 \right)\\ \vdots\\ R\left(1,M-2 \right)\\ R\left(1,M-1 \right)\\ R\left(1,M \right)\end{bmatrix}$

 

 

이렇게 구현하면, 대부분의 케이스는 해결됐습니다.

 

이제부터는 이 방법으로 구할 수 없는 케이스들을 알고 그것들을 예외처리하는 과정입니다.

 

첫번째는 $N=1$인 케이스입니다.

 

$N=1$일 경우 한번 출발할 지점을 정하면 더 이상 이동을 할 필요가 없이 끝입니다.

 

즉 $R\left ( 1,k \right )=1$ 입니다. (단, $1\leq k\leq M$)

 

따라서 출발지점으로 고를 수 있는 열의 개수 $M$이 답이 됩니다.

 

 

두번째는 $N>1$ 이고 동시에 $M=1$ 인 케이스입니다.

 

이 경우, $1$번 행에서 더 이상 움직일 수 있는 칸이 없습니다.

 

따라서 $N$번 행에 도착하는 방법의 수가 0이 됩니다.

 

 

마지막으로, $M=2$인 케이스입니다.

 

$M=2$ 일 때는 아주 독특한 해답이 나오니 직접 구해보는 게 좋습니다.

 

$N=1$ 일 때, $R\left ( 1,1 \right)=R\left ( 1,2 \right)=1$ 입니다.

 

$N=2$ 일 때, $R\left ( 2,1 \right)=R\left ( 2,2 \right)=1$ 입니다.

 

$N=3$ 일 때, $R\left ( 3,1 \right)=R\left ( 3,2 \right)=2$ 입니다.

 

$N=4$ 일 때, $R\left ( 4,1 \right)=R\left ( 4,2 \right)=2$ 입니다.

 

$N=5$ 일 때, $R\left ( 5,1 \right)=R\left ( 5,2 \right)=4$ 입니다.

 

$N=6$ 일 때, $R\left ( 6,1 \right)=R\left ( 6,2 \right)=4$ 입니다.

 

$N=7$ 일 때, $R\left ( 7,1 \right)=R\left ( 7,2 \right)=8$ 입니다.

 

$N=8$ 일 때, $R\left ( 8,1 \right)=R\left ( 8,2 \right)=8$ 입니다.

 

 

답은 $2^{\large \left \lceil \frac{N}{2} \right \rceil}$ 입니다.

 

이제 모든 케이스에 대한 답이 나오도록 구현하면 됩니다.

 

코드는 다음과 같습니다.

 

#include <stdio.h>
#define mod 1000000007

typedef struct {
	long long array[30][30];
} Matrix;

void Matrix_print (Matrix object, int size);

long long power_modular (long long base, long long power);

Matrix matrix_multiply_modular (Matrix A, Matrix B, int size);
Matrix matrix_power_modular (Matrix A, long long power, int size);

int main() {
	long long N;
	int M;
	scanf("%lld %d", &N, &M);
	
	if (N == 1) {
		printf("%d", M);
		return 0;
	}
	else if (M == 1) { // N > 1, M = 1
		printf("0");
		return 0;
	}
	else if (M == 2) {
		
		long long answer;
		if (N % 2) {
			answer = power_modular(2, (N+1)/2);
		}
		else {
			answer = power_modular(2, N/2);
		}
		
		printf("%lld", answer);
		return 0;
	}
	else {
		
		int size = M;
		
		Matrix Answer;
		for (int i = 0; i < size; i++) {
			Answer.array[i][0] = 1;
			for (int j = 1; j < size; j++) {
				Answer.array[i][j] = 0;
			}
		}
		
		Matrix Base1;
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				if (i == 0) {
					if (j <= 1) {
						Base1.array[i][j] = 1;
					}
					else {
						Base1.array[i][j] = 0;
					}
				}
				else if (i == size - 1) {
					if (j >= size - 2) {
						Base1.array[i][j] = 1;
					}
					else {
						Base1.array[i][j] = 0;
					}
				}
				else {
					if (j == i - 1 || j == i || j == i + 1) {
						Base1.array[i][j] = 1;
					}
					else {
						Base1.array[i][j] = 0;
					}
				}
			}
		}
		
		Matrix Base2;
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				if (i == 0) {
					if (j == 1) {
						Base2.array[i][j] = 1;
					}
					else {
						Base2.array[i][j] = 0;
					}
				}
				else if (i == size - 1) {
					if (j == size - 2) {
						Base2.array[i][j] = 1;
					}
					else {
						Base2.array[i][j] = 0;
					}
				}
				else {
					if (j == i - 1 || j == i + 1) {
						Base2.array[i][j] = 1;
					}
					else {
						Base2.array[i][j] = 0;
					}
				}
			}
		}
	
		long long power = N / 2;
	
		if (N % 2) {
			Base1 = matrix_power_modular(Base1, power, size);
		}
		else {
			Base1 = matrix_power_modular(Base1, power - 1, size);
		}
		Base2 = matrix_power_modular(Base2, power, size);
	
		Answer = matrix_multiply_modular(Base2, Answer, size);
		Answer = matrix_multiply_modular(Base1, Answer, size);
	
		long long answer = 0;
		for (int i = 0; i < M; i++) {
			answer = (answer + Answer.array[i][0]) % mod;
		}
	
		printf("%lld", answer);
		return 0;
	}
}

void Matrix_print (Matrix object, int size) {
	for (int i = 0; i < size; i++) {
		for (int j = 0; j < size; j++) {
			printf("%lld ", object.array[i][j]);
		}
		printf("\n");
	}
	printf("\n");
}

long long power_modular(long long base, long long power) {
	base %= mod;
	long long result = 1;
	while(power) {
		if (power % 2) {
			result = (result * base) % mod;
		}
		base = (base * base) % mod;
		power /= 2;
	}
	return result;
}

Matrix matrix_multiply_modular (Matrix A, Matrix B, int size) {
	Matrix result;
	for (int i = 0; i < size; i++) {
		for (int j = 0; j < size; j++) {
			result.array[i][j] = 0;
			for (int k = 0; k < size; k++) {
				long long temp = (A.array[i][k] * B.array[k][j]) % mod;
				result.array[i][j] = (result.array[i][j] + temp) % mod;
			}
		}
	}
	return result;
}

Matrix matrix_power_modular (Matrix A, long long power, int size) {
	Matrix result;
	for (int i = 0; i < size; i++) {
		for (int j = 0; j < size; j++) {
			if (i == j) {
				result.array[i][j] = 1;
			}
			else {
				result.array[i][j] = 0;
			}
		}
	}
	while(power) {
		if (power % 2) {
			result = matrix_multiply_modular (result, A, size);
		}
		A = matrix_multiply_modular (A, A, size);
		power /= 2;
	}
	return result;
}

 

(C11, 1116KB, 12ms, 제출번호 26334509)


다른 문제들에선 Base 역할을 하는 행렬이 하나만 있었는데

 

이 문제에선 두 개를 써서 신선한 문제였습니다.