1. 程式人生 > >NYOJ 1000 又見斐波那契數列

NYOJ 1000 又見斐波那契數列

又見斐波那契數列
時間限制:1000 ms | 記憶體限制:65535 KB
難度:4
描述
斐波那契數列大家應該很熟悉了吧。下面給大家引入一種新的斐波那契數列:M斐波那契數列。 M斐波那契數列F[n]是一種整數數列,它的定義如下:

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

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

題解

F(0)=a,F(1)=b
F(n)=F(n−1)F(n−2)
⇒F(n)=F(n−2)2F(n−3)
⇒F(n)=F(n−3)3F(n−4)2
⇒F(n)=F(n−4)5F(n−5)3

⇒F(n)=F(1)f(n)F(0)f(n−1)
⇒F(n)=bf(n)af(n−1)
f(n)正是斐波那契數列。
矩陣快速冪可以求出f(n),f(n−1)的值。
然後快速冪計算bf(n),af(n−1), 答案就是兩者乘積。
需要注意一點,取模是對F(n)取模,不是f(n),那麼問題來了,f(n)會是一個很大的數,如果不模一下根本存不下,怎麼辦呢?
這裡的模 p=1000000007,是個素數,由尤拉定理,
a^x≡a^(x%(p-1))(mod p)
所以f(n)可以對 p−1取模。
斐波那契數列就用矩陣快速冪去求:

這裡寫圖片描述

最後再快速冪取模 GG

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
#define mod 1000000007
#define PI acos(-1.0)
typedef long long LL;
typedef
vector<LL> vec; typedef vector<vec> mat; // A*B mat mul(mat& A, mat& B) { mat C(A.size(), vec(B[0].size())); for(int i = 0; i < (int)A.size(); ++i) for(int j = 0; j < (int)B[0].size(); ++j) for(int k = 0; k < (int)B.size(); ++k) C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % (mod - 1); return C; } // A^n mat pow_mat(mat A, LL n) { mat B(A.size(), vec(A.size())); for(int i = 0; i < (int)A.size(); ++i) B[i][i] = 1; while(n) { if(n & 1) B = mul(B, A); A = mul(A, A); n >>= 1; } return B; } LL quickpowmod(LL x,LL y,LL mo) { LL ret = 1; while(y){ if(y&1) ret = ret*x%mo; x = x*x%mod; y >>= 1; } return ret; } LL a,b,n; LL ans(LL a,LL b,LL n){ mat A(2,vec(2)); A[0][0]=1; A[0][1]=1; A[1][0]=1; A[1][1]=0; A=pow_mat(A,n); LL x=A[1][0],y=A[1][1]; return (quickpowmod(b,x,mod)*quickpowmod(a,y,mod))%mod; } int main(){ while(cin>>a>>b>>n){ if(n==0)printf("%lld\n",a); else if(n==1)printf("%lld\n",b); else printf("%lld\n",ans(a,b,n)); } return 0; }