백준문제풀이

백준 문제 11444번 피보나치 수 6 문제풀이 c++

노가다 김씨 2022. 2. 20. 03:51

https://www.acmicpc.net/problem/11444

 

11444번: 피보나치 수 6

첫째 줄에 n이 주어진다. n은 1,000,000,000,000,000,000보다 작거나 같은 자연수이다.

www.acmicpc.net

문제해석

이 문제는 행렬을 이용해서 피보나치 수를 빠르게 구할수 있는 방법을 사용해야한다

피보나치 수열은 첫 두항을 제외하면 다음과 같은데

이 식을 행렬로 나타내면

 

이렇게 쓰면 Fn+2=Fn+1 + Fn 식은 만족하고 초록색 행렬의 아래 부분은 모순이 없게 적당히 채워주면 된다.

그렇게 완성한 행렬은 다음과 같다.

이 식으로 부터 

빨간 부분의 식을 얻을 수있고 F0은 0이므로

1 1

1 0 의 n-1제곱의 1행 1열이 Fn값이 된다.

이걸 바탕으로 코드를 작성했다.

 

코드

#include <iostream>
#include <stack>
typedef long long int ll;
using namespace std;
void ans_ans();
void ans_base();
stack <bool> st;
ll base[2][2]={1,1,1,0};
ll ans[2][2]={1,1,1,0};
ll tmp[2][2];
int main(){
    cout.tie(NULL);
    cin.tie(NULL);
    ios_base::sync_with_stdio(false);
    ll n;
    cin>>n;
    if(n==1)
    {
        cout<<1;
    }
    else
    {
        n=n-1;
        while(n!=0)
        {
            st.push(n&1);
            n=n>>1;
        }
        st.pop();
        while(!st.empty())
        {
            if(st.top()==1)
            {
                ans_ans();
                ans_base();
                //ans=ans*ans*base
            }
            else
            {

                ans_ans();
                //ans=ans*ans
            }
            st.pop();
        }
        cout<<ans[0][0];
    }
}
void ans_base(){
    //ans=ans*ans*base
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            for(int k=0; k<2; k++)
            {
                tmp[i][j]=((tmp[i][j]%1000000007)+(ans[i][k]%1000000007)*(base[k][j]%1000000007))%1000000007;
            }
        }
    }
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            ans[i][j]=tmp[i][j];
            tmp[i][j]=0;
        }
    }
}
void ans_ans(){
    //ans=ans*ans
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            for(int k=0; k<2; k++)
            {
                tmp[i][j]=((tmp[i][j]%1000000007)+(ans[i][k]%1000000007)*(ans[k][j]%1000000007))%1000000007;
            }
        }
    }
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            ans[i][j]=tmp[i][j];
            tmp[i][j]=0;
        }
    }
}