在ACM中,许多复杂的递推关系式往往和斐波那契数列有着密切的关系,而一旦和斐波那契数列关系上了,你不用多想了,这题一定得用到矩阵&快速幂。因为斐波那契数列是没有通项公式的。
首先我们得先了解一般斐波那契数列的矩阵求法。斐波那契数列的定义是F(0)=0,F(1)=1之后的项就是前两项之和。经过计算可得
A={1 1 B={1 1 A*B的n次方即斐波那契数列的n+2项。即我们要求第n项,须得先求B方阵的n-2次。而这一步就需要用到快速幂,快速幂的效率是n(log
0 0} 1 0} (n)),n就可以很大了。
矩阵+快速幂的斐波那契数列代码:


#include<iostream> #include<stdio.h> using namespace std; #define mdu 1000000007; #define N 15 struct matrix { __int64 a[N][N]; }; matrix chu,die; matrix mul(matrix a1,matrix a2,int ii) { int i,j,k; matrix c; for(i=1;i<=ii;i++) for(j=1;j<=ii;j++) { c.a[i][j]=0; for(k=1;k<=ii;k++) c.a[i][j]+=a1.a[i][k]*a2.a[k][j]%mdu; c.a[i][j]%=mdu; } return c; } void qmi(__int64 nn) { while(nn>0) { if(nn%2==1) chu=mul(chu,die,2); die=mul(die,die,2); nn=nn>>1; } } int main() { __int64 n; while(scanf("%I64d",&n)!=EOF) { chu.a[1][1]=1; chu.a[1][2]=1; chu.a[2][1]=0; chu.a[2][2]=0; die.a[1][1]=1; die.a[1][2]=1; die.a[2][1]=1; die.a[2][2]=0; if(n!=1 || n!=2) qmi(n-2); printf("%The number is:%I64d\n",chu.a[1][1]); } return 0; }
我们再来看几个典型例题:
M斐波那契数列
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1050 Accepted Submission(s): 312
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 )


#include<iostream> #include<stdio.h> using namespace std; #define mdu 1000000007 #define N 15 struct matrix { __int64 a[N][N]; }; matrix chu,die; matrix mul(matrix a1,matrix a2,int ii) { int i,j,k; matrix c; for(i=1;i<=ii;i++) for(j=1;j<=ii;j++) { c.a[i][j]=0; for(k=1;k<=ii;k++) c.a[i][j]=(c.a[i][j]+a1.a[i][k]*a2.a[k][j])%(mdu-1); } return c; } __int64 kmi(__int64 a,__int64 x) { __int64 temp=a; __int64 cnt=1; while(x>0) { if(x%2==1) cnt=cnt*temp%mdu; temp=temp*temp%mdu; x=x>>1; } return cnt; } void qmi(__int64 nn) { while(nn>0) { if(nn%2==1){ matrix c; c.a[1][1]=kmi(chu.a[1][1],die.a[1][1])*kmi(chu.a[1][2],die.a[2][1])%mdu; c.a[1][2]=kmi(chu.a[1][1],die.a[1][2])*kmi(chu.a[1][2],die.a[2][2])%mdu; chu=c; } die=mul(die,die,2); nn=nn>>1; } } int main() { __int64 n,a,b; while(scanf("%I64d%I64d%I64d",&a,&b,&n)!=EOF) { chu.a[1][1]=b; chu.a[1][2]=a; chu.a[2][1]=0; chu.a[2][2]=0; die.a[1][1]=1; die.a[1][2]=1; die.a[2][1]=1; die.a[2][2]=0; if(n==0) { printf("%I64d\n",chu.a[1][2]); continue; } if(n==1) { printf("%I64d\n",chu.a[1][1]); continue; } qmi(n-1); printf("%I64d\n",chu.a[1][1]); } return 0; }
我们再来看一题:
Lucky Coins Sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 627 Accepted Submission(s): 329


#include<iostream> #include<stdio.h> using namespace std; #define mdu 10007; #define N 15 struct matrix { __int64 a[N][N]; }; matrix chu,die; matrix mul(matrix a1,matrix a2,int ii) { int i,j,k; matrix c; for(i=1;i<=ii;i++) for(j=1;j<=ii;j++) { c.a[i][j]=0; for(k=1;k<=ii;k++) { c.a[i][j]+=a1.a[i][k]*a2.a[k][j]%mdu; } c.a[i][j]%=mdu; } return c; } void qmi(__int64 nn) { int i,j; while(nn>0) { if(nn%2==1) chu=mul(chu,die,3); die=mul(die,die,3); nn=nn>>1; } } int main() { __int64 n; while(scanf("%I64d",&n)!=EOF) { chu.a[1][1]=2; chu.a[1][2]=2; chu.a[1][3]=2; chu.a[2][1]=0; chu.a[2][2]=0; chu.a[2][3]=0; chu.a[3][1]=0; chu.a[3][2]=0; chu.a[3][3]=0; die.a[1][1]=2; die.a[1][2]=0; die.a[1][3]=0; die.a[2][1]=1; die.a[2][2]=1; die.a[2][3]=1; die.a[3][1]=0; die.a[3][2]=1; die.a[3][3]=0; if(n==0 || n==1 || n==2){ printf("0\n"); continue; } if(n==3){ printf("2\n"); continue; } qmi(n-3); printf("%I64d\n",chu.a[1][1]); } return 0; }