1. 程式人生 > >HDU 4549 M斐波那契數列(矩陣快速冪+費馬小定理)

HDU 4549 M斐波那契數列(矩陣快速冪+費馬小定理)

M斐波那契數列

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 3476    Accepted Submission(s): 1080


Problem Description M斐波那契數列F[n]是一種整數數列,它的定義如下:

F[0] = a
F[1] = b
F[n] = F[n-1] * F[n-2] ( n > 1 )

現在給出a, b, n,你能求出F[n]的值嗎?
Input 輸入包含多組測試資料;
每組資料佔一行,包含3個整數a, b, n( 0 <= a, b, n <= 10^9 )
Output 對每組測試資料請輸出一個整數F[n],由於F[n]可能很大,你只需輸出F[n]對1000000007取模後的值即可,每組資料輸出一行。
Sample Input 0 1 0 6 10 2
Sample Output 0 60
Source

中文題意。

POINT://其實還沒學過矩陣到底怎麼算,只知道2乘2的。

學習矩陣快速冪,可以用來求斐波那契數列。畢竟n非常大,遞迴肯定超時。

自己理解了一下,寫了一個很醜的矩陣快速冪,只能求斐波那契數列。

費馬小定理2:

我們可以利用費馬小定理來簡化冪模運算:由於a^(p-1)≡a^0≡1(mod p),所以a^x(mod p)有迴圈節,長度為p-1,所以a^x≡a^(x%(p-1))(mod p)


#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>
#include <algorithm>
#include <math.h>
using namespace std;
#define ll long long
const ll p =1e9+7;
const ll m=p-1;
    ll a,b,n;
struct node
{
    ll x11,x12,x21,x22;
};
node chen(node a,node b)
{
    node ans;
    (ans.x11=a.x11*b.x11+a.x12*b.x21)%=m;
    (ans.x12=a.x11*b.x12+a.x12*b.x22)%=m;
    (ans.x21=a.x21*b.x11+a.x22*b.x21)%=m;
    (ans.x22=a.x21*b.x12+a.x22*b.x22)%=m;
    return ans;
}
node jqkm(node now,ll mi)
{
    if(mi<=0) return now;
    node ans;
    ans.x11=1,ans.x12=0,ans.x21=0,ans.x22=1;
    while(mi)
    {
        if(mi&1)
        {
            ans=chen(ans,now);
        }
        mi=mi>>1;
        now=chen(now,now);
    }
    return ans;
}
ll qkm(ll now, ll mi)
{
    ll ans=1;
    while(mi)
    {
        if(mi&1)
            (ans*=now)%=p;
        mi=mi>>1;
        (now=now*now)%=p;
    }
    return ans;
}
ll baoli(ll x)
{
    if(x==0) return a;
    if(x==1) return b;
    return baoli(x-1)*baoli(x-2)%p;
}
int main()
{
    while(~scanf("%lld %lld %lld",&a,&b,&n))
    {
        ll f1=1,f2=2;
        ll na,nb;
        if(n<4)
        {
            printf("%lld\n",baoli(n));
        }
        else
        {
            node ans;
            node now;
            now.x11=1,now.x12=1,now.x21=1,now.x22=0;
            ans=jqkm(now,n-3);
            nb=ans.x11*f2+ans.x12*f1;
            na=ans.x21*f2+ans.x22*f1;
            printf("%lld\n",qkm(a,na)*qkm(b,nb)%p);
        }
    }
}