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;
}