백준문제풀이

백준 문제 2086번 피보나치 수의 합 문제풀이 c++

노가다 김씨 2022. 2. 25. 08:10

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

 

2086번: 피보나치 수의 합

제 1항과 제 2항을 1이라 하고, 제 3항부터는 앞의 두 항의 합을 취하는 수열을 피보나치(fibonacci) 수열이라고 한다. 예를 들어 제 3항은 2이며, 제 4항은 3이다. 피보나치 수열의 a번째 항부터 b번째

www.acmicpc.net

 

문제해석

피보나치 F0부터 Fn까지의 합을 Sn이라고 새롭게 정의하면 위 그림과 같다.

즉 Sn=Fn+2 - 1 이므로 Fa부터 Fb까지의 합을 이 식을 통해 구하는것이 가능하다.

Sb-Sa-1이 Fa부터 Fb까지 합이 되므로 우리가 얻어야하는 것은 Fb+2와 Fa+1이 된다.

저번 게시글 https://anwltjdzheldsbql.tistory.com/15 에 사용했던 분할정복을 통한 수열의 거듭제곱 코드를

그대로 가져와서 조금만 바꾸어서 풀었다.

코드

#include <iostream>
#include <stack>
#include <vector>
typedef long long int ll;
using namespace std;
void reset();
void ans_ans();
void ans_base();
vector <ll> v;
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);
    for(int i=0; i<2; i++)
    {
        ll n;
        cin>>n;
        if(i==0)
        {
            n=n+1;
        }
        else
        {
            n=n+2;
        }
        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();
        }
        v.push_back(ans[0][0]);
        reset();
    }
    if(v[1]-v[0]<0)
    {
        cout<<1000000000+v[1]-v[0];
    }
    else
    {
        cout<<v[1]-v[0];
    }
}
void reset(){
    ans[0][0]=base[0][0];
    ans[0][1]=base[0][1];
    ans[1][0]=base[1][0];
    ans[1][1]=base[1][1];
}
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]%1000000000)+(ans[i][k]%1000000000)*(base[k][j]%1000000000))%1000000000;
            }
        }
    }
    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]%1000000000)+(ans[i][k]%1000000000)*(ans[k][j]%1000000000))%1000000000;
            }
        }
    }
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            ans[i][j]=tmp[i][j];
            tmp[i][j]=0;
        }
    }
}