P1962 斐波那契数列-题解(矩阵乘法扩展)

https://www.luogu.org/problemnew/show/P1962(题目传送)

n的范围很大,显然用普通O(N)的递推求F(n)铁定超时了。这里介绍一种用矩阵快速幂实现的解法:

首先普及一下矩阵乘法:

一个m*q的m行q列的矩阵A*一个q*n的q行n列的矩阵B得到一个m*n的m行n列的矩阵AB,则有:

通俗的讲,就是新矩阵第i行j列的数等于第一个矩阵第i行的q个数分别乘第二个矩阵的第j列的q个数并把它们加起来的和。注意,矩阵乘法满足结合律和分配律,但不满足交换律。

我们可以把第n项F(n)、第n-1项F(n-1)写成一个1*2的矩阵[Fn  Fn-1] 并考虑怎样由前面的[Fn-1  Fn-2]推过来。可以先把[Fn  Fn-1]写成[1*Fn-1+1*Fn-2  ​1*Fn-1+0*Fn-2]的形式,试推导一个矩阵base,使

[Fn-1  Fn-2]*base=[Fn  Fn-1]=[Fn-1+Fn-2  Fn-1],因为Fn-1和Fn-2都在结果矩阵的第一列以系数为1的形式出现,结果矩阵是一个1*2的矩阵,所以base为一个2*2的矩阵,且第一列为1,1;

Fn-1和Fn-2在结果矩阵的第二列以系数为1、0的形式出现,所以结果矩阵第二列为1,0。即base= ,[Fn-1  Fn-2]*=[Fn  Fn-1]。

同理可以推出[Fn-2  Fn-3]**=[Fn  Fn-1]…………[F2 F1]*^(n-2)=[Fn Fn-1]。

此时本题的核心便是计算出base=的n-2次方就行了,可以用矩阵快速幂做(换汤不换药)

代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const long long mod=1000000007;
 6 struct matrix{                    //用结构体构建矩阵类型 
 7     long long a[3][3];
 8 }ans,a;
 9 int init()                        //初始化矩阵。ans存放题解中提到的1*2的矩阵,这里为了统一用同一种矩
10                                 //阵乘法的处理,又发现若矩阵的一行(或一列)全为0,则乘法的结果矩阵
11                                 //的对应行(或列)也全为0,不影响结果,便用0把ans扩充成2*2的矩阵了 。 
12 {
13     ans.a[1][1]=ans.a[1][2]=1;
14     a.a[1][1]=a.a[1][2]=a.a[2][1]=1;
15 }
16 matrix operator *(matrix a,matrix b)//矩阵乘法实现(运算符重载) 
17 {
18     matrix c;
19     for(int i=1;i<=2;i++)
20         for(int j=1;j<=2;j++) c.a[i][j]=0;
21     for(int i=1;i<=2;i++)
22         for(int j=1;j<=2;j++)
23             for(int k=1;k<=2;k++)
24             c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
25     return c;        
26 }
27 int main()
28 {
29     long long n;
30     cin>>n;
31     if(n<=2)
32     {
33         cout<<1;
34         return 0;
35     }
36     long long b=n-2;
37     init();
38     while(b)                    //万年不变的快速幂 
39     {
40         if(b&1) ans=ans*a;
41         a=a*a;
42         b>>=1;
43     }
44     cout<<ans.a[1][1];
45     return 0;
46 }
原文地址:https://www.cnblogs.com/InductiveSorting-QYF/p/10679484.html