M斐波那契数列F[n]是一种整数数列,它的定义如下:
F[0] = a
F[1] = b
F[n] = F[n-1] * F[n-2] ( n > 1 )
现在给出a, b, n,你能求出F[n]的值吗?
思路:首先我们很容易得到F[n]的通项公式,对于F[n]=a^(f[n-1])*b^(f[n]),其中f[n]为斐波那契数列的第n项。由于我们要求的n很大(最大可达到10^9),所以我们不能直接求,这时我们可以用矩阵加速用O(logn)的复杂度来求f[n],然后再用乘方快速幂求最终的结果。但是我们这里要求的结果是模上1000000007后(设为mod)的值,所以在矩阵加速的时候不能直接模上mod。这里用到了一个数论的知识,就是若a,b互质,则a^(b-1)%b==1,因为mod是一个素数,所以对于任何a,b(a,b<=10^9),都与mod互质,所以我们最终即是求 a^(f[n-1]%(mod-1))*b^(f[n]%(mod-1))%mod,这下就可以用矩阵快速幂来求解了。
代码如下:
#include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> #define maxn 3 #define mod 1000000006 using namespace std; typedef long long LL; LL c[100][maxn][maxn]; LL ans[maxn][maxn]; int m=2; void init(LL a[maxn][maxn],LL b[maxn][maxn], LL c[maxn][maxn]) { int i,j,k; LL tmp[maxn][maxn]; memset(tmp,0,sizeof(tmp)); for(i=1;i<=m;i++) { for(j=1;j<=m;j++) { for(k=1;k<=m;k++) { tmp[i][j]+=b[i][k]*c[k][j]; tmp[i][j]%=mod; } } } for(i=1;i<=m;i++) { for(j=1;j<=m;j++) a[i][j]=tmp[i][j]; } } void build(int num) { if(num==1) return; build(num-1); init(c[num],c[num-1],c[num-1]); } LL abmodn(LL a,LL b,LL n) { LL d=1,i,bi[40],num=0; while(b>0) { bi[num++]=b%2; b/=2; } for(i=num-1;i>=0;i--) { d=(d*d)%n; if(bi[i]) d=(a*d)%n; } return d; } void solve(int n,int a,int b) { memset(ans,0,sizeof(ans)); int t[55],num=0; while(n) { t[++num]=n%2; n/=2; } build(num); int i,j; for(i=1;i<=m;i++) { for(j=1;j<=m;j++) ans[i][j]=c[num][i][j]; } for(i=1;i<num;i++) { if(t[i]) { init(ans,ans,c[i]); } } LL x=(ans[1][1]+ans[2][1])%mod,y=(ans[1][2]+ans[2][2])%mod; LL ANS=(abmodn(a,x,mod+1)*abmodn(b,y,mod+1))%(mod+1); printf("%I64d\n",ANS); } int main() { // freopen("dd.txt","r",stdin); c[1][1][1]=0; c[1][2][1]=c[1][1][2]=c[1][2][2]=1; int a,b,n; while(scanf("%d%d%d",&a,&b,&n)!=EOF) { if(n==0) printf("%d\n",a); else if(n==1) printf("%d\n",b); else if(n==2) printf("%I64d\n",(LL)a*b%(mod+1)); else { solve(n-2,a,b); } } return 0; }