zoukankan      html  css  js  c++  java
  • 【洛谷P1962】斐波那契数列

    Description

    给定n,求斐波那契数列第n项对1e9+7取模的值

    Solution

    由于数据太大,朴素的递推会超时,所以我们考虑用矩阵优化。

    首先我们要明确矩阵乘法的运算法则,假设A是一个n*m的矩阵,B是一个m*p的矩阵,C是一个n*p的矩阵且满足C=A*B,那么存在

    $$C_{i,j}=sumlimits_{k=1}^{m}{A_{i,k}*B_{k,j}}$$

    举一个简单的例子就能直观的反映这个式子:

    $$
    left[
    egin{matrix}
    2 & 3 \
    4 & 5
    end{matrix}
    ight] imes
    left[
    egin{matrix}
    6 \
    7
    end{matrix}
    ight] =
    left[
    egin{matrix}
    2*6+3*7 \
    4*6+5*7
    end{matrix}
    ight]
    $$

    然后我们考虑如何优化斐波那契数列

     我们假设$Fib(n)$表示一个矩阵

    $
    left[
    egin{matrix}
    f_{n} & f_{n-1}
    end{matrix}
    ight]
    $,那么我们希望有一个矩阵base,使得$Fib(n-1) imes base = Fib(n)$,也就是我们希望这样:

    $$
    left[
    egin{matrix}
    f_{n - 1} & f_{n - 2}
    end{matrix}
    ight] imes base =
    left[
    egin{matrix}
    f_{n} & f_{n-1}
    end{matrix}
    ight]$$

    那么我们显然可以看出

    $$base=left[egin{matrix}1 & 1 \1 & 0end{matrix} ight] $$

    所以,我们定义初始矩阵$ans=left[egin{matrix} f_1 & f_2end{matrix} ight] $然后计算$ans imes base^{n-2}$即可

    关于计算结果,我们可以定义结构体并且重载乘号使得矩阵乘法可以直接运算,关于乘方运算我们可以类比整数快速幂来实现矩阵快速幂

    时间复杂度为$O(2^3log_2{n})$

    Code

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int mod = 1e9 + 7;
     4 typedef long long ll;
     5 ll n;
     6 struct Matrix {
     7     ll m[3][3];
     8     Matrix() {
     9         memset(m, 0, sizeof(m));
    10     }
    11     Matrix operator *(const Matrix &x) const {
    12         Matrix ret;
    13         for (register int i = 1; i <= 2; ++i)
    14             for (register int j = 1; j <= 2; ++j)
    15                 for (register int k = 1; k <= 2; ++k)
    16                     ret.m[i][j] = (ret.m[i][j] + m[i][k] * x.m[k][j]) % mod;
    17         return ret; 
    18     }
    19 } a, base;
    20 void qpow(ll p) {
    21     while (p) {
    22         if (p & 1) a = a * base;
    23         base = base * base;
    24         p >>= 1;
    25     }
    26 }
    27 int main() {
    28     scanf("%lld", &n);
    29     if (n <= 2) {
    30         puts("1");
    31         return 0;
    32     }
    33     base.m[1][1] = base.m[1][2] = base.m[2][1] = 1;
    34     a.m[1][1] = a.m[1][2] = 1;
    35     qpow(n - 2);
    36     printf("%lld
    ", a.m[1][1] % mod);
    37     return 0;
    38 }
    AC Code
  • 相关阅读:
    Java虚拟机JVM学习05 类加载器的父委托机制
    java 接口
    java 抽象类
    代码块(2)
    获取超额收益的思考
    HttpServer
    交易过程思考
    A股时间窗口
    redash学习记录
    MySQL学习记录
  • 原文地址:https://www.cnblogs.com/shl-blog/p/11335378.html
Copyright © 2011-2022 走看看