반응형
1. gcd(f(m), f(n)) = f(gcd(m, n))이다.
2. 유클리드 호제법을 이용하여 gcd(m, n)을 구한다.
3. 분할 정복을 이용하여 gcd(m, n)번째 피보나치 수를 구한다.
1. gcd(f(m), f(n)) = f(gcd(m, n))이다.
위와 같은 피보나치의 성질을 이용해서 푸는 문제였다. 증명은 여기를 참고했다. https://math.hmc.edu/funfacts/fibonacci-gcds-please/
2. 유클리드 호제법을 이용하여 gcd(m, n)을 구한다.
먼저 m과 n의 최대 공약수를 구해야 한다. 유클리드 호제법을 사용하여 O(logN)에 구해준다.
3. 분할 정복을 이용하여 gcd(m, n)번째 피보나치 수를 구한다.
피보나치 수열을 행렬의 거듭제곱으로 나타낸 뒤, 행렬의 거듭제곱 값을 분할 정복을 이용해서 O(logN)에 구해준다.
반응형
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
typedef vector<vector<ll>> Matrix;
const ll MOD = 1000000007;
ll N, M;
Matrix A = {{1, 1}, {1, 0}};
ll gcd(ll a, ll b) {
if (b == 0) return a;
return gcd(b, a%b);
}
Matrix matrixMultiply(Matrix a, Matrix b) {
int R = a.size();
int C = b[0].size();
int K = b.size();
Matrix ret = Matrix(R, vector<ll>(C, 0));
for (int i=0; i<R; i++) {
for (int j=0; j<C; j++) {
for (int k=0; k<K; k++) {
ret[i][j] += (a[i][k] * b[k][j]) % MOD;
ret[i][j] %= MOD;
}
}
}
return ret;
}
Matrix matrixPower(Matrix m, ll n) {
if (n == 1) return m;
Matrix half = matrixPower(m, n/2);
if (n % 2 == 0) return matrixMultiply(half, half);
else return matrixMultiply(matrixMultiply(half, half), m);
}
ll fibonacci(ll n) {
if (n == 1) return 1;
else return matrixPower(A, n-1)[0][0];
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> N >> M;
if (N > M) swap(N, M);
// gcd(f(m), f(n)) = f(gcd(m, n));
cout << fibonacci(gcd(N, M));
return 0;
}
반응형
'Problem Solving > BOJ' 카테고리의 다른 글
백준 11780번 플로이드 2 - C++ 풀이 (0) | 2022.07.25 |
---|---|
백준 17135번 캐슬 디펜스 - C++ 풀이 (0) | 2022.07.24 |
백준 1561번 놀이 공원 - C++ 풀이 (0) | 2022.07.21 |
백준 1113번 수영장 만들기 - C++ 풀이 (0) | 2022.07.20 |
백준 2086번 피보나치 수의 합 - C++ 풀이 (0) | 2022.07.19 |
댓글