Baekjoon Review
[Gold 2] 11444 피보나치 수 6
hanseongbugi
2024. 9. 13. 17:07
https://www.acmicpc.net/problem/11444
초기 점화식을 사용해 DP로 문제를 해결하고자 하였다.
하지만, 문제 조건 중 N의 최대 값이 1,000,000,000,000,000,000인 것을 알게 되었으며
실제로 DP로 문제 접근 시 시간 초과가 발생 하였다.
따라서 이 문제는 DP가 아닌 정복 분할 형태로 해결해야한다.
피보나치의 점화식은 다음과 같다.
FIBO[N + 2] = FIBO[N-1] + FIBO[N]
위 점화식을 사용해서 2로 분할하면 아래와 같은 수식을 새울 수 있다.
F[n] = F[n-1] + F[n-2]
F[n] = F[n-1] + F[n-2] + F[n-2] + F[n-3] = 3F[n-2] + 2F[n-3]
F[n] = 5F[n-3] + 3F[n-4]
F[n] = 8F[n-4] + 5F[n-5]
F[n] = F[k+1]F[n-k] + F[k]F[n-k-1]
=> F[n] = F[n/2+1]F[n/2] + F[n/2]F[n/2-1]
=> F[2n] = F[n+1]F[n] + F[n]F[n-1] = F[n]x(F[n+1] + F[n-1])
= F[n]x(2F[n-1] + F[n]) // 짝수일때
=> F[2n+1] = F[n+1]^2 + F[n]^2
두 식을 N에 대해서 나타내면 다음과 같다.
F[n] = F[n/2]x(2F[n/2-1] + F[n/2])
F[n] = F[(n+1)/2]^2 + F[(n-1)/2]^2
#include <iostream>
#include <map>
using namespace std;
long long N;
map<long long, long long> f;
long long fibo(long long num){
if(num == 0) return 0;
if(num == 1) return 1;
if(num == 2) return 1;
if(f.count(num) > 0) return f[num];
if(num % 2 == 0){
long long m = num / 2;
long long temp1 = fibo(m - 1);
long long temp2 = fibo(m);
f[num] = ((2 * temp1 + temp2) * temp2) % 1000000007;
return f[num];
}
long long m = (num + 1) / 2;
long long temp1 = fibo(m);
long long temp2 = fibo(m - 1);
f[num] = (temp1 * temp1 + temp2 * temp2) % 1000000007;
return f[num];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin>>N;
cout<<fibo(N);
}