矩阵加速计算学习

矩阵加速运算学习笔记

矩阵加速运算是解决一些递推问题的高效方法,尤其是在处理大规模数据时。本文将通过三篇逐步深入的内容,帮助读者理解矩阵加速的核心思想和应用。


第一篇:矩阵快速幂的模板学习

题目链接

1. 矩阵乘法基础

矩阵乘法是矩阵加速的基础运算。给定两个矩阵 $ A $ 和 $ B $,若 $ A $ 是 $ m \times n $ 的矩阵,$ B $ 是 $ n \times p $ 的矩阵,则它们的乘积 $ C $ 是一个 $ m \times p $ 的矩阵,其中:

\[C[i][j] = \sum_{k=1}^{n} A[i][k] \cdot B[k][j] \]

需要注意的是,矩阵乘法满足结合律,但不满足交换律。

2. 矩阵快速幂

类似整数的快速幂,矩阵快速幂用于高效计算矩阵的高次幂。核心思想是利用分治法将幂次分解为更小的部分进行计算。具体步骤如下:

  1. 初始化结果矩阵 $ res $ 为单位矩阵(对角线元素为 1,其余元素为 0)。
  2. 当幂次 $ k > 0 $ 时:
    • 若 $ k $ 为奇数,将当前矩阵 $ A $ 乘入结果矩阵 $ res $。
    • 将矩阵 $ A $ 自身平方(即 $ A = A \times A $),并将幂次 $ k $ 右移一位(相当于 $ k = k / 2 $)。
  3. 最终得到的结果矩阵 $ res $ 即为 $ A^k $。

3. 模板代码

以下是实现矩阵快速幂的模板代码:

#include <bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;

struct Matrix {
    int a[101][101];
    int n; // 矩阵大小
    Matrix(int size) : n(size) {
        memset(a, 0, sizeof(a));
    }
    void build_identity() { // 构造单位矩阵
        for (int i = 1; i <= n; i++) a[i][i] = 1;
    }
};

Matrix operator*(const Matrix &a, const Matrix &b) {
    Matrix c(a.n);
    for (int k = 1; k <= a.n; k++)
        for (int i = 1; i <= a.n; i++)
            for (int j = 1; j <= a.n; j++)
                c.a[i][j] = (c.a[i][j] + 1LL * a.a[i][k] * b.a[k][j]) % MOD;
    return c;
}

Matrix matrix_pow(Matrix a, long long k) {
    Matrix res(a.n);
    res.build_identity(); // 初始化为单位矩阵
    while (k > 0) {
        if (k & 1) res = res * a;
        a = a * a;
        k >>= 1;
    }
    return res;
}

void solve() {
    int n;
    long long k;
    cin >> n >> k;
    Matrix mat(n);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> mat.a[i][j];

    Matrix result = matrix_pow(mat, k);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++)
            cout << result.a[i][j] << " ";
        cout << "\n";
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
}

4. 总结

通过矩阵快速幂,我们可以高效地计算矩阵的高次幂。这在后续递推问题中是非常重要的工具。


第二篇:斐波那契数列的学习

题目链接

1. 斐波那契数列定义

斐波那契数列是一个经典的递推数列,定义如下:

\[F_1 = F_2 = 1, \quad F_n = F_{n-1} + F_{n-2} \quad (n \geq 3) \]

当 $ n $ 很大时(如 $ n \leq 10^{18} $),直接递推会导致超时。因此,我们需要借助矩阵加速来优化计算。

2. 矩阵形式的递推关系

我们将斐波那契数列用矩阵表示:

\[\begin{bmatrix} F_n \\ F_{n-1} \end{bmatrix} = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \cdot \begin{bmatrix} F_{n-1} \\ F_{n-2} \end{bmatrix} \]

进一步展开,可以得到:

\[\begin{bmatrix} F_n \\ F_{n-1} \end{bmatrix} = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^{n-2} \cdot \begin{bmatrix} F_2 \\ F_1 \end{bmatrix} \]

3. 矩阵加速实现

根据上述公式,我们可以通过矩阵快速幂计算 $ F_n $。初始矩阵为:

\[\text{base} = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}, \quad \text{ans} = \begin{bmatrix} 1 \\ 1 \end{bmatrix} \]

最终结果为 $ \text{ans} \times \text{base}^{n-2} $ 的第一个元素。

4. 示例代码

以下是实现斐波那契数列的代码:

#include <bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;

struct Matrix {
    int a[2][2];
    Matrix() {
        memset(a, 0, sizeof(a));
    }
    void build_base() {
        a[0][0] = a[0][1] = a[1][0] = 1;
        a[1][1] = 0;
    }
};

Matrix operator*(const Matrix &a, const Matrix &b) {
    Matrix c;
    for (int k = 0; k < 2; k++)
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
                c.a[i][j] = (c.a[i][j] + 1LL * a.a[i][k] * b.a[k][j]) % MOD;
    return c;
}

Matrix matrix_pow(Matrix a, long long k) {
    Matrix res;
    res.a[0][0] = res.a[1][1] = 1; // 单位矩阵
    while (k > 0) {
        if (k & 1) res = res * a;
        a = a * a;
        k >>= 1;
    }
    return res;
}

void solve() {
    long long n;
    cin >> n;
    if (n <= 2) {
        cout << 1 << "\n";
        return;
    }
    Matrix base;
    base.build_base();
    Matrix res = matrix_pow(base, n - 2);
    cout << (res.a[0][0] + res.a[0][1]) % MOD << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
}

5. 总结

通过矩阵加速,我们可以在 $ O(\log n) $ 时间内计算出第 $ n $ 个斐波那契数,极大地提高了效率。


题目链接

第三篇:斐波那契公约数

1. 题目描述

给定两个正整数 $ n $ 和 $ m $,求斐波那契数列中第 $ n $ 项和第 $ m $ 项的最大公约数,即 $ \gcd(F_n, F_m) $。结果对 $ 10^8 $ 取模。

2. 数学结论

斐波那契数列具有以下性质:

\[\gcd(F_n, F_m) = F_{\gcd(n, m)} \]

这意味着,我们只需要先计算 $ \gcd(n, m) $,然后求出对应的斐波那契数即可。

3. 实现步骤

  1. 使用欧几里得算法计算 $ \gcd(n, m) $。
  2. 利用矩阵加速计算斐波那契数列的第 $ \gcd(n, m) $ 项。
  3. 输出结果并对 $ 10^8 $ 取模。

4. 示例代码

以下是完整代码实现:

#include <bits/stdc++.h>
using namespace std;

const int MOD = 1e8;

struct Matrix {
    int a[2][2];
    Matrix() {
        memset(a, 0, sizeof(a));
    }
    void build_base() {
        a[0][0] = a[0][1] = a[1][0] = 1;
        a[1][1] = 0;
    }
};

Matrix operator*(const Matrix &a, const Matrix &b) {
    Matrix c;
    for (int k = 0; k < 2; k++)
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
                c.a[i][j] = (c.a[i][j] + 1LL * a.a[i][k] * b.a[k][j]) % MOD;
    return c;
}

Matrix matrix_pow(Matrix a, long long k) {
    Matrix res;
    res.a[0][0] = res.a[1][1] = 1; // 单位矩阵
    while (k > 0) {
        if (k & 1) res = res * a;
        a = a * a;
        k >>= 1;
    }
    return res;
}

long long gcd(long long a, long long b) {
    return b ? gcd(b, a % b) : a;
}

void solve() {
    long long n, m;
    cin >> n >> m;
    long long g = gcd(n, m);
    if (g <= 2) {
        cout << 1 << "\n";
        return;
    }
    Matrix base;
    base.build_base();
    Matrix res = matrix_pow(base, g - 2);
    cout << (res.a[0][0] + res.a[0][1]) % MOD << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
}

5. 总结

通过数学结论和矩阵加速,我们可以在 $ O(\log n) $ 时间内高效解决斐波那契公约数问题。


posted @ 2025-04-08 11:21  archer2333  阅读(125)  评论(0)    收藏  举报