안녕하세요.
오늘은 백준 11444번: 피보나치 수 6(링크) 문제를 풀어보려고 합니다.
문제
피보나치 수는 0과 1로 시작한다. 0번째 피보나치 수는 0이고, 1번째 피보나치 수는 1이다. 그 다음 2번째 부터는 바로 앞 두 피보나치 수의 합이 된다.
이를 식으로 써보면 Fn = Fn-1 + Fn-2 (n ≥ 2)가 된다.
n=17일때 까지 피보나치 수를 써보면 다음과 같다.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597
n이 주어졌을 때, n번째 피보나치 수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 n이 주어진다. n은 1,000,000,000,000,000,000보다 작거나 같은 자연수이다.
출력
첫째 줄에 n번째 피보나치 수를 1,000,000,007으로 나눈 나머지를 출력한다.
예제 입력
1000
예제 출력
517691607
제한
시간 제한: 1초
메모리 제한: 256MB
풀이
행렬 제곱을 풀고나면 쉽게 해결되는 문제이다.
먼저 피보나치 일반항은 흔히 아래와 같은 식으로 알려져있다.
그러나 이 문제는 저 식을 사용해 dp로 해결하기엔 최대 n = 1,000,000,000,000,000,000 이기에 시간초과가 날 것이다.
그래서 여기서는 저 피보나치 식을 행렬 곱으로 바꾸어 표현한다.
f(n+1)과 f(n)의 식을 먼저 적고, 이를 다음과 같이 행렬로 나타낸다.
이후 위 식을 정리하면 아래와 같이 일반적으로 나타낼 수 있게 된다.
이때 구하고자 하는 피보나치 수는 행렬의 (1,0)번째로 가져오면 된다.
종합적으로 행렬 곱셈과 분할 정복을 이용한 거듭제곱을 사용해서 풀어주면 된다.
정답
더보기
#include <iostream>
using namespace std;
using ll = long long;
ll n;
ll m = 1000000007;
struct matrix {
int size = 2;
ll element[2][2] = { {0,0},{0,0} };
matrix& operator*(const matrix& b) {
matrix newMatrix = matrix();
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
for (int k = 0; k < size; k++) {
newMatrix.element[i][k] += (this->element[i][j] * b.element[j][k] % m)%m;
}
}
}
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
this->element[i][j] = newMatrix.element[i][j]%m;
}
}
return *this;
}
};
matrix pow(matrix a, ll k) {
if (k == 1) return a;
matrix tmp = pow(a, k / 2);
if (k % 2 == 0) return tmp * tmp;
return tmp * tmp * a;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> n;
matrix a = matrix();
a.element[0][0] = 1;
a.element[0][1] = 1;
a.element[1][0] = 1;
a.element[1][1] = 0;;
a = pow(a, n);
cout << a.element[1][0];
return 0;
}
이렇게 해서 백준 11444번 피보나치 수 6 문제를 풀어보았습니다.
댓글로 질문을 남기시면 성실히 답해드리겠습니다
감사합니다!
참고
'PS > 백준 문제' 카테고리의 다른 글
[BOJ][C++] 11401번 이항 계수 3 (0) | 2024.10.26 |
---|---|
[BOJ][C++] 2342번 Dance Dance Revolution (1) | 2024.10.16 |
[BOJ][C++] 10830번 행렬 제곱 (0) | 2024.10.14 |
[BOJ][C++] 7579번 앱 (2) | 2024.10.13 |
[BOJ][C++] 25682번 체스판 다시 칠하기 2 (3) | 2024.10.10 |