문제 : https://www.acmicpc.net/problem/11778
[알고리즘풀이]
먼저, 피보나치에 관한 수학적 정리를 이용해야 문제를 해결할 수 있습니다.
gcd(a,b) = g 라고 했을 때, gcd( fibonacci(a), fibonacci(b) ) = fibonacci(g) 이다.
즉, a번 째 피보나치 수와 b번 째 피보나치 수의 최대공약수는 a, b의 최대공약수번 째 피보나치 수와 같습니다.
이 정리를 이용해, 우리는 fibonacci(gcd(a,b)) 를 구하면 됩니다.
gcd(a,b) 는 유클리드 호제법을 이용해서 빠르게 구할 수 있고,
fibonacci(gcd(a,b))는 행렬의 곱셈을 이용해서 문제를 해결할 수 있습니다.
( 유사 문제 풀이 : https://travelbeeee.tistory.com/92?category=817856 )
#include<iostream>
#define m 1000000007
#define ll long long
using namespace std;
ll a,b, fib_n, fib_m, ta, tb;
ll gcd(ll a, ll b) {
if (b > a) {
ll t = a;
a = b;
b = t;
}
while (b) {
ll r = a % b;
a = b;
b = r;
}
return a;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> a >> b;
ll GCD = gcd(a, b);
ll M[2][2] = { {1,1},{1,0} };
ll A[2][2] = { {1,0},{0,1} };
ta = GCD - 1;
while (ta) {
if (ta % 2 == 1) {
// A * M 을 A에 갱신.
ll temp[2][2] = {};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
// A[i][j] = A[i][j] * M[i][j];
for (int k = 0; k < 2; k++) {
temp[i][j] += ( M[i][k] * A[k][j] ) % m;
}
}
}
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
A[i][j] = temp[i][j];
}
// M * M을 갱신.
ll temp[2][2] = {};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
// M[i][j] = M[i][j] * M[i][j];
for (int k = 0; k < 2; k++) {
temp[i][j] += (M[i][k] * M[k][j]) % m;
}
}
}
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
M[i][j] = temp[i][j];
ta /= 2;
}
cout << A[0][0] % m;
}
'Problem Solving > BOJ' 카테고리의 다른 글
[BOJ] 12840 : 창용이의 시계 -travelbeeee (0) | 2019.10.31 |
---|---|
[BOJ] 12847 : 꿀 아르바이트 - travelbeeee (0) | 2019.10.31 |
[BOJ] 16234 : 인구 이동 - travelbeeee (0) | 2019.10.30 |
[BOJ] 11728 : 배열 합치기 -travelbeeee (0) | 2019.10.30 |
[BOJ] 1958 : LCS 3 - travelbeeee (0) | 2019.10.29 |