斐波那契 -- 矩阵快速幂

acwing算法竞赛进阶指南打卡活动——数学知识——斐波那契

前置知识

快速幂,矩阵乘法

题意

在斐波那契数列中, F 0 = 0 , F 1 = 1 , F n = F n − 1 + F n − 2 ( n > 1 ) . F_0=0,F_1=1,F_n=F_{n-1}+F_{n-2}(n>1). F0=0,F1=1,Fn=Fn1+Fn2(n>1).
给定整数 n n n ,求 F n   m o d   10000. F_n \space mod \space 10000. Fn mod 10000.

数据范围: 0 ≤ n ≤ 2 × 1 0 9 0 \le n \le 2 \times 10^9 0n2×109

思路

可以注意到这题的数据范围特别大,如果直接使用递推的话会超时,所以这题需要用矩阵快速幂来加速递推。

矩阵快速幂

首先把递推关系写成矩阵的形式
[ F n F n − 1 ] = [ F n − 1 + F n − 2 F n − 1 ] \left[ \begin{matrix} F_{n}&F_{n-1} \end{matrix} \right]= \left[ \begin{matrix} F_{n-1} + F_{n-2} & F_{n-1} \end{matrix} \right] [FnFn1]=[Fn1+Fn2Fn1]
将等号右边改写为矩阵乘法的形式
[ F n F n − 1 ] = [ F n − 1 F n − 2 ] [ 1 1 1 0 ] \left[ \begin{matrix} F_{n}&F_{n-1} \end{matrix} \right]= \left[ \begin{matrix} F_{n-1} & F_{n-2} \end{matrix} \right] \left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right] [FnFn1]=[Fn1Fn2][1110]
又因为
[ F n − 1 F n − 2 ] = [ F n − 2 F n − 3 ] [ 1 1 1 0 ] \left[ \begin{matrix} F_{n-1}&F_{n-2} \end{matrix} \right]= \left[ \begin{matrix} F_{n-2} & F_{n-3} \end{matrix} \right] \left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right] [Fn1Fn2]=[Fn2Fn3][1110]
所以
[ F n F n − 1 ] = [ F n − 2 F n − 3 ] [ 1 1 1 0 ] 2 ⋮ [ F n F n − 1 ] = [ F 1 F 0 ] [ 1 1 1 0 ] n − 1 \left[ \begin{matrix} F_{n}&F_{n-1} \end{matrix} \right]= \left[ \begin{matrix} F_{n-2} & F_{n-3} \end{matrix} \right] \left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right]^2\\ \vdots \\ \left[ \begin{matrix} F_{n}&F_{n-1} \end{matrix} \right]= \left[ \begin{matrix} F_{1} & F_{0} \end{matrix} \right] \left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right]^{n-1} [FnFn1]=[Fn2Fn3][1110]2[FnFn1]=[F1F0][1110]n1
为了统一逻辑,我们在代码中这样实现
[ F n + 1 F n 0 0 ] = [ F 1 F 0 0 0 ] [ 1 1 1 0 ] n \left[ \begin{matrix} F_{n+1} & F_{n} \\ 0 & 0 \end{matrix} \right]= \left[ \begin{matrix} F_{1} & F_{0} \\ 0 & 0 \end{matrix} \right] \left[ \begin{matrix} 1 & 1 \\ 1 & 0 \end{matrix} \right]^n [Fn+10Fn0]=[F10F00][1110]n
这样可以只定义一个矩阵乘法方法且避免特殊判断第0项的情况。
令最终结果矩阵为 D D D,我们要求的 F n Fn Fn 就在 D 12 . D_{12}. D12.

code

#include 
#include 
#include 
using namespace std;

const int N = 2, mod = 10000;
int n;

struct matrix 
{
    int a[N][N];
    matrix() 
    {
        memset(a, 0, sizeof(a));    
    }
    // 重写乘号为矩阵乘法
    matrix operator *(const matrix &b)
    {
        matrix c;
        for (int i = 0; i < N; i ++ )
            for (int j = 0; j < N; j ++ )
                for (int k = 0; k < N; k ++ )
                    c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j]) % mod;
        return c;
    }
};

// 快速幂
matrix quick_pow(matrix &M, int p) 
{
    matrix res;
    res.a[0][0] = res.a[1][1] = 1; // 对角矩阵,相当于连乘初始化变量为1
    while (p > 0)
    {
        if (p & 1) res = res * M; // 因为重写了*不能用 res *= M
        p >>= 1;
        M = M * M;
    }
    return res;
}

int main() 
{
    while (cin >> n, ~n) 
    {
        matrix A, B;
        A.a[0][0] = 1;
        B.a[0][0] = B.a[0][1] = B.a[1][0] = 1;
        matrix res = A * quick_pow(B, n);
        cout << res.a[0][1] << endl;
    }
    return 0;
}

复杂度

时间复杂度: O ( log ⁡ n ) O(\log{n}) O(logn)
空间复杂度: O ( 1 ) O(1) O(1)

你可能感兴趣的:(矩阵,算法,c++)