반응형
1. N층짜리 건물에 객실을 배치하는 방법의 수를 점화식으로 나타낸다.
2. 점화식을 행렬의 곱으로 나타낸다.
3. 분할정복을 이용하여 행렬의 거듭제곱을 계산한다.
1. N층짜리 건물에 객실을 배치하는 방법의 수를 점화식으로 나타낸다.
T(n) = N층짜리 건물에 객실을 배치하는 방법의 수
T(n) = A(n) + B(n) + C(n)
A(n) = n층은 비워두는 경우의 수
B(n) = n층은 1호실을 채우는 경우의 수
C(n) = n층은 2호실을 채우는 경우의 수
n번째 층의 상태에 따라 n-1번째 층의 상태를 결정하는 경우가 달라진다.
- n번째 층이 비어있다면: n-1번째 층은 비울수도, 1호실만 채울수도, 2호실만 채울수도 있다.
- n번째 층의 1호실을 채웠다면: n-1번째 층은 비우거나 2호실만 채울 수 있다.
- n번째 층의 2호실을 채웠다면: n-1번째 층은 비우거나 1호실만 채울 수 있다.
A(n) = A(n-1) + B(n-1) + C(n-1)
B(n) = A(n-1) + C(n-1)
C(n) = A(n-1) + B(n-1)
이때 1호실만 채우는 경우와 2호실만 채우는 경우는 대칭이므로 B(n) = C(n)이다. 따라서 아래와 같은 점화식으로 표현할 수 있다.
Count(n) = A(n) + 2*B(n)
A(n) = A(n-1) + 2*B(n-1)
B(n) = A(n-1) + B(n-1)
2. 점화식을 행렬의 곱으로 나타낸다.
N=10^18이므로 점화식을 순차계산하면 시간초과가 발생한다. 점화식을 빠르게 계산할 수 있는 방법으로 행렬의 곱을 활용하는 방법이 있다. 위의 점화식을 행렬곱으로 표현하면 아래와 같다. [An, Bn]은 [[1, 2], [1, 1]]이라는 2X2행렬을 n-1번 거듭제곱한 뒤, [A1, B1]인 [1, 1]과 곱해준 결과가 된다.
3. 분할정복을 이용하여 행렬의 거듭제곱을 계산한다.
MxM 행렬의 N 거듭제곱을 순차 계산하면 O(M^3 * N)의 시간복잡도가 들게 된다. 따라서 N=10^18로는 시간초과가 발생하게 된다. 하지만 분할정복을 이용하여 구현하면 O(M^3 * logN)에 계산이 가능하다.
반응형
#include <iostream>
using namespace std;
typedef pair<long long, long long> pll;
typedef pair<pll, pll> matrix22;
long long MOD = 1000000007;
long long N;
matrix22 A = {{1, 2}, {1, 1}};
matrix22 multiply(matrix22 a, matrix22 b) {
matrix22 ret = {{0, 0}, {0, 0}};
ret.first.first += a.first.first * b.first.first % MOD; ret.first.first %= MOD;
ret.first.first += a.first.second * b.second.first % MOD; ret.first.first %= MOD;
ret.first.second += a.first.first * b.first.second % MOD; ret.first.second %= MOD;
ret.first.second += a.first.second * b.second.second % MOD; ret.first.second %= MOD;
ret.second.first += a.second.first * b.first.first % MOD; ret.second.first %= MOD;
ret.second.first += a.second.second * b.second.first % MOD; ret.second.first %= MOD;
ret.second.second += a.second.first * b.first.second % MOD; ret.second.second %= MOD;
ret.second.second += a.second.second * b.second.second % MOD; ret.second.second %= MOD;
return ret;
}
matrix22 power(long long n) {
if (n == 1) return A;
matrix22 half = power(n/2);
if (n % 2 == 0) return multiply(half, half);
else return multiply(multiply(half, half), A);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> N;
if (N == 1) cout << 3;
else {
matrix22 A_pow = power(N-1);
long long an = (A_pow.first.first + A_pow.first.second) % MOD;
long long bn = (A_pow.second.first + A_pow.second.second) % MOD;
cout << ((2 * bn % MOD) + an) % MOD;
}
return 0;
}
반응형
'Problem Solving > BOJ' 카테고리의 다른 글
백준 24551번 일이 너무 많아... - 파이썬(Python) 풀이 (0) | 2022.02.28 |
---|---|
백준 24508번 나도리팡 - C++(cpp) 풀이 (0) | 2022.02.23 |
백준 16637번 괄호 추가하기 - C++(cpp) 풀이 + 그림 설명 (0) | 2022.02.18 |
백준 17298번 오큰수 - C++(cpp) 풀이 + 그림 설명 (0) | 2022.02.17 |
백준 3055번 탈출 - C++(cpp) 풀이 (0) | 2022.02.17 |
댓글