1. 程式人生 > >洛谷——P1349 廣義斐波那契數列

洛谷——P1349 廣義斐波那契數列

分享 for iostream amp size alt 以及 hide pre

題目描述

廣義的斐波那契數列是指形如an=p*an-1+q*an-2的數列。今給定數列的兩系數p和q,以及數列的最前兩項a1和a2,另給出兩個整數n和m,試求數列的第n項an除以m的余數。

輸入輸出格式

輸入格式:

輸入包含一行6個整數。依次是p,q,a1,a2,n,m,其中在p,q,a1,a2整數範圍內,n和m在長整數範圍內。

輸出格式:

輸出包含一行一個整數,即an除以m的余數。

輸入輸出樣例

輸入樣例#1:
1 1 1 1 10 7
輸出樣例#1:
6

說明

數列第10項是55,除以7的余數為6。

我們來通過這個題講一下斐波那契數列怎麽用矩陣乘法來優化吧

我們知道對於斐波那契數列我們有這樣的遞推式:f[n]=f[n-1]+f[n-2]

通常情況下,我們計算f(n)的時間復雜度就是O(n)(分別計算f(1), f(2) ... f(n - 1)).
但是當n很大又或者還有其他處理的復雜度一疊加便會超時。

所以當n很大的時候,我們的遞推式便不起作用了,我們應該像一種辦法來優化一下這個遞推式,怎麽辦呢,我們看到這個式子有加,有乘,我們就一般會想到矩陣乘法(這時候就有人會問了,博主,你眼瞎啊,明明就是個加法的式子,你說他有乘法。。。)額、、對於這個問題,我們可以將上面的式子做一個小小的變形,將它變成f[n]=f[n-1]*1+f[n-2]*1, f[n-1]=f[n-1]*1+f[n-2]*0

我們在這個地方普及一下矩陣乘法優化遞推式的特征:形如f(n) = a1 * f(n - 1) + a2 * f(n - 2) + ... + ak * f(n - k)+c (c為常數)

然後我們可以將他組成這樣的一個矩陣

技術分享

然後我們進行矩陣乘法

來,看看代碼:

技術分享
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mod 100000000
using namespace std;
int n;
int read()
{
    
int x=0,f=1; char ch=getchar(); while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();} while(ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar(); return x*f; } struct Node { long long m[3][3]; Node(){memset(m,0,sizeof(m));} }mb,ans; int GCD(int a,int b) { if(b==0) return a; return GCD(b,a%b); } Node operator*(Node a,Node b) { Node c; for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) for(int k=1;k<=2;k++) c.m[i][j]=(c.m[i][j]%mod+a.m[i][k]*b.m[k][j]%mod)%mod; return c; } int main() { n=read();n--; mb.m[1][1]=mb.m[1][2]=mb.m[2][1]=1; ans.m[1][1]=ans.m[2][2]=1; while(n) { if(1&n) ans=ans*mb; mb=mb*mb;n>>=1; } cout<<ans.m[1][1]; return 0; }
矩陣乘法優化斐波那契

對於這個式子,我們可以根據樸素的斐波那契的矩陣乘法的形式將式子推出來

技術分享

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
long long q,p,a1,a2,n,mod;
long long read()
{
    long long x=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
    return x*f;
}
struct Node 
{
    long long m[3][3];
    Node(){memset(m,0,sizeof(m));}
}begin,ans;
Node operator*(Node a,Node b)
{
    Node c;
    for(int i=1;i<=2;i++)
     for(int j=1;j<=2;j++)
      for(int k=1;k<=2;k++)
       c.m[i][j]=(c.m[i][j]%mod+(a.m[i][k]%mod*b.m[k][j]%mod)%mod)%mod;
    return c;
}
int main()
{
    p=read(),q=read(),a1=read(),a2=read();
    n=read(),mod=read();n-=2;
    ans.m[1][1]=a2,ans.m[1][2]=a1;
    begin.m[1][1]=p,begin.m[2][1]=q,begin.m[1][2]=1;
    while(n)
    {
        if(n&1) ans=ans*begin;
        begin=begin*begin;
        n>>=1;
    }
    if(n+2==1) cout<<ans.m[1][2]%mod;
    else cout<<ans.m[1][1]%mod;
    return 0;
}

洛谷——P1349 廣義斐波那契數列