斐波那契數列(矩陣加速遞推)


題目背景

大家都知道,斐波那契數列是滿足如下性質的一個數列:

• f(1) = 1

• f(2) = 1

• f(n) = f(n-1) + f(n-2) (n ≥ 2 且 n 為整數)

題目描述

請你求出 f(n) mod 1000000007 的值。

輸入輸出格式

輸入格式:

·第 1 行:一個整數 n

輸出格式:

第 1 行: f(n) mod 1000000007 的值

(n<=1e18)

思路:

我們已經知道遞推公式了,但有個問題,就是n太大

怎么辦呢?

我前面寫過一個矩陣快速冪的板子,大家應該看過。

那么,這里我們就要用矩陣快速冪來優化

我們將原數列抽象為這樣的一個矩陣:

{  fn  , 0 }

{fn-1,0}

那么,我們將原矩陣乘上這樣的一個矩陣:
{1,1}

{1,0}

就變成了這樣:

{fn+fn-1,0}

{    fn    ,0}

整個矩陣向着斐波那契的下一項方向移動

OK,現在我們就不用O(n)地移動了,O(logn)即可

(關於矩陣快速冪部分,請參見我以前的一篇博客(上面有鏈接))

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#define rii register int i
#define rij register int j
#define rik register int k
#define mod 1000000007
using namespace std;
struct j{
    long long jz[5][5];
}x,y,z,an;
long long n;
long long ys[5];
inline j cheng(j l,j r)
{
    j ltt;
    long long ans=0;
    ltt.jz[1][1]=0;
    ltt.jz[1][2]=0;
    ltt.jz[2][1]=0;
    ltt.jz[2][2]=0;
    for(rii=1;i<=2;i++)
    {
        for(rij=1;j<=2;j++)
        {
            ans=0;
            for(rik=1;k<=2;k++)
            {
                ans+=(l.jz[i][k]*r.jz[k][j]);
                ans%=mod;
            }
            ltt.jz[i][j]=ans;
        }
    }
    return ltt;
}
j pw(j k,long long c)
{
    if(c==1)
    {
        y=cheng(y,k);
        return y;
    }
    if(c%2==0)
    {
        k=cheng(k,k);
        pw(k,c/2);
    }
    else
    {
        c--;
        y=cheng(k,y); 
        pw(k,c);
    }
}
int main()
{
    x.jz[1][1]=1;
    x.jz[1][2]=1;
    x.jz[2][1]=1;
    y.jz[1][1]=1;
    y.jz[2][2]=1;
    an.jz[1][1]=1;
    an.jz[2][1]=1;
    scanf("%lld",&n);
    if(n==1)
    {
        cout<<1;
        return 0;
    }
    if(n==2)
    {
        cout<<"1";
        return 0;
    }
    pw(x,n-2);
    an=cheng(y,an);
    cout<<an.jz[1][1];
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM