矩阵快速幂

矩阵的定义:

矩阵就用二维数组存储,在结构体中也保存了矩阵的行数、列数 (m、n)。

在矩阵之间的计算中需要行数和列数的信息,与其在用到时指定,不如和矩阵二维数组一同放在结构体内,初始化时赋值。

把初始化的构造函数放在结构体内,就不用在外部使用前每次手动初始化,很方便。

由于经常要用到矩阵相乘,就直接重载了 * ,不用每次调用函数。

#include <memory.h>
typedef long long ll;
const int MOD = 1e9+7;
const int MAXN = 3;

struct mat {
    ll c[MAXN][MAXN];
    int m, n;                               //表示矩阵的行数、列数
    mat(int a, int b) : m(a), n(b) {        //构造函数初始化
        memset(c, 0, sizeof(c));
    }
    mat operator * (const mat& temp) {      //重载运算符 *
        mat ans(m, temp.n);
        for (int i = 0; i < m; i ++)
            for (int j = 0; j < temp.n; j ++)
                for (int k = 0; k < n; k ++)
                    ans.c[i][j] = (ans.c[i][j] + c[i][k] * temp.c[k][j] % MOD) % MOD;
        return ans;
    }
};

矩阵快速幂:

求矩阵的幂时,也有快速幂计算,这里可以参考普通的快速幂算法。复杂度为 O(\log n) 

mat mat_pow(mat M, int n) {                     //矩阵快速幂
    mat ans(M.m, M.m);
    for (int i = 0; i < M.m; i ++)
        ans.c[i][i] = 1;
    while (n > 0) {
        if (n & 1) ans = ans * M;
        M = M * M;
        n >>= 1;
    }
    return ans;
}

应用:

在求递推公式时很好用。就拿最简单的斐波那契数列举例,该数列满足:

F_{0}=0

F_{1}=1

F_{n+2}=F_{n+1}+F_{n}

若要求第 10^{15} 项时,显然直接递推是不实际的。这里应该借助矩阵来做,把递推公式改写成如下:

\binom{F_{n+2}}{F_{n+1}}=\begin{pmatrix} 1 & 1\\ 1& 0 \end{pmatrix}\binom{F_{n+1}}{F_{n}}

因此,可以推出

\binom{F_{n}}{F_{n-1}}=\begin{pmatrix} 1 & 1\\ 1& 0 \end{pmatrix}^{n-1}\binom{1}{0}

所以只需要用矩阵快速幂求出   \begin{pmatrix} 1 & 1\\ 1& 0 \end{pmatrix}^{n-1} 便可很快地求出结果。

挑战上总结了更为一般的情况:

举个例子,好理解一些:

F_{1}=A

F_{2}=B

F_{n}=C*F_{n-2}+D*F_{n-1}+k

改写成矩阵递推公式就是

\begin{pmatrix} F_{n}\\ F_{n-1}\\ 1 \end{pmatrix}=\begin{pmatrix} D & C & k\\ 1 & 0&0 \\ 0 & 0 & 1 \end{pmatrix}^{n-2}\begin{pmatrix} B\\ A\\ 1 \end{pmatrix}

送一题:https://blog.csdn.net/Originum/article/details/82111066

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值