zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    JS写游戏
    为运算表达式设计优先级
    原子的数量
    二叉搜索树的范围和
    所有可能的满二叉树
    有效的井字游戏
    站在对象模型的尖端
    执行期语意学
    构造、析构、拷贝语意学
    [CSP-S模拟测试]:序列(二分答案+树状数组)
  • 原文地址:https://www.cnblogs.com/InductiveSorting-QYF/p/10679484.html
Copyright © 2011-2022 走看看