알고리즘/백준

[백준][C++] 11444: 피보나치 수 6

KANTAM 2023. 9. 21. 14:11

문제

풀이

  • 일반적인 다이나믹 프로그래밍으로 해결하려고 하면 메모리 초과

  • 위의 식을 이용하여 피보나치 수열을 행렬의 거듭제곱으로 계산할 수 있다.
  • 분할 정복을 이용한 거듭제곱으로 해결한다.

코드

#include <iostream>
#include <vector>
#include <map>

using namespace std;

#define MOD 1000000007

map<long long, vector<vector<long long>>> cache;

vector<vector<long long>> matrix = {
    {1, 1},
    {1, 0}
};

vector<vector<long long>> mulMatrix(vector<vector<long long>> m1, vector<vector<long long>> m2)
{
    vector<vector<long long>> outM = {
        {0, 0},
        {0, 0}
    };

    outM[0][0] = (m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0]) % MOD;
    outM[0][1] = (m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1]) % MOD;
    outM[1][0] = (m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0]) % MOD;
    outM[1][1] = (m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1]) % MOD;

    return outM;
}

vector<vector<long long>> fibonacci(long long n)
{
    if (n == 1)
    {
        return matrix;
    }

    // cache가 있을 때는 cache반환
    if (!cache[n].empty())
    {
        return cache[n];
    }

    if (n % 2 == 0)
    {
        cache[n] = mulMatrix(fibonacci(n / 2), fibonacci(n / 2));
        return cache[n];
    }
    else
    {
        cache[n] = mulMatrix(fibonacci(n - 1), fibonacci(1));
        return cache[n];
    }
}

int main()
{
    long long n;
    cin >> n;

    cache[1] = matrix;

    vector<vector<long long>> answer = fibonacci(n);

    cout << answer[0][1];

    return 0;
}