HDU 4549 M斐波那契數列(矩陣快速冪+費馬小定理)
阿新 • • 發佈:2019-02-17
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); } } }