矩阵加速

矩阵加速

Thu Oct 03 2024
zzcoe
5 分钟

快速斐波那契数列#

[[快速幂#矩阵快速幂|矩阵快速幂]]是求解斐波那契数列的一个高效方法,特别是当需要计算的斐波那契数非常大时。斐波那契数列定义如下:

F(n)=F(n1)+F(n2)对于所有n2F(n) = F(n-1) + F(n-2) \quad \text{对于所有} \, n \geq 2

其中,F(0)=0F(0) = 0F(1)=1F(1) = 1

斐波那契数列与矩阵乘法#

斐波那契数列可以通过矩阵乘法来表示。考虑以下矩阵:

(1110)\begin{pmatrix} 1 & 1 \\ 1 & 0 \\ \end{pmatrix}

将这个矩阵称为矩阵 AA。现在,如果我们计算 AAnn 次幂,并将结果与矩阵 (F(1)F(0))=(10)\begin{pmatrix} F(1) \\ F(0) \end{pmatrix} = \begin{pmatrix} 1 \\ 0 \end{pmatrix} 相乘,我们将得到一个包含 F(n+1)F(n+1)F(n)F(n) 的矩阵:

An(10)=(F(n+1)F(n))A^n \begin{pmatrix} 1 \\ 0 \end{pmatrix} = \begin{pmatrix} F(n+1) \\ F(n) \end{pmatrix}

这意味着通过计算矩阵 AAnn 次幂,我们可以直接得到斐波那契数列中的第 nn 项。

如何使用[[快速幂#矩阵快速幂|矩阵快速幂]]计算#

矩阵快速幂算法允许我们高效地计算矩阵 AA 的幂。基本思想是利用幂的性质:A2n=(An)2A^{2n} = (A^n)^2A2n+1=A×(An)2A^{2n+1} = A \times (A^n)^2。这意味着我们可以通过递归地平方矩阵来减少乘法的次数,从而以对数时间复杂度计算矩阵的幂。这种方法比直接计算每个斐波那契数要高效得多,特别是对于大数。

示例代码#

以下是一个简单的示例,展示了如何使用矩阵快速幂来计算斐波那契数列的第 nn 项:

CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <vector>

using namespace std;

typedef vector<vector<int>> Matrix;

Matrix multiplyMatrix(const Matrix& a, const Matrix& b) {
    int n = a.size();
    Matrix result(n, vector<int>(n, 0));
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            for (int k = 0; k < n; ++k) {
                result[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    return result;
}

Matrix quickPow(Matrix a, int power) {
    int n = a.size();
    Matrix result(n, vector<int>(n, 0));
    for (int i = 0; i < n; ++i) {
        result[i][i] = 1;
    }
    while (power > 0) {
        if (power & 1) {
            result = multiplyMatrix(result, a);
        }
        a = multiplyMatrix(a, a);
        power >>= 1;
    }
    return result;
}

int fibonacci(int n) {
    if (n <= 1) {
        return n;
    }
    Matrix mat = {{1, 1}, {1, 0}};
    Matrix result = quickPow(mat, n - 1);
    return result[0][0];
}

int main() {
    int n = 10; // 计算第10个斐波那契数
    cout << "Fibonacci(" << n << ") = " << fibonacci(n) << endl;
    return 0;
}

这段代码定义了如何使用矩阵快速幂来计算斐波那契数列的第 nn 项。通过计算矩阵 AAn1n-1 次幂,我们可以直接得到 F(n)F(n)。这种方法的时间复杂度是 O(logn)O(\log n),远远优于直接递归计算的 O(2n)O(2^n) 或线性迭代的 O(n)O(n)

例题1213. 斐波那契 - AcWing题库提示f[1]=f[3]f[2]f[1]=f[3]-f[2] 所以有

f[1]+f[2]+f[3]+...+f[n]=(f[3]f[2])+(f[4]f[3])+(f[5]f[4])+...+(f[n+2]f[n1])=f[n+2]f[2]=f[n+2]1\begin{align} f[1]&+f[2]+f[3]+...+f[n]=(f[3]-f[2])+(f[4]-f[3])+(f[5]-f[4])+...\\ &+(f[n+2]-f[n-1])=f[n+2]-f[2]=f[n+2]-1 \end{align}

得到 i=1nf[i]=f[n+2]1\sum_{i=1}^{n}f[i]=f[n+2]-1