矩阵快速幂

本文只做基础入门,了解矩阵快速幂的基础应用。进阶内容可以去看其他dalao的~~

矩阵乘法

矩阵乘法
设 A = ( a i j ) 是 一 个 m × x 矩 阵 , B = ( b i j ) 是 一 个 s × n 矩 阵 , 那 么 规 定 矩 阵 A 和 矩 阵 B 的 乘 积 是 一 个 m × n 矩 阵 C = ( c i j ) 设A=(a_{ij})是一个m×x矩阵,B=(b_{ij})是一个s×n矩阵,那么规定矩阵A和矩阵B的乘积是一个m×n矩阵C=(c_{ij}) A=(aij)m×xB=(bij)s×nABm×nC=(cij)

( a 11 a 12 a 13 a 21 a 22 a 23 ) ( b 11 b 12 b 21 b 22 b 31 b 32 ) = ( a 11 b 11 + a 12 b 21 + a 13 b 31 a 11 b 12 + a 12 b 22 + a 13 b 32 a 21 b 11 + a 22 b 21 + a 23 b 31 a 21 b 12 + a 22 b 22 + a 23 b 32 ) \begin{gathered} \begin{pmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \end{pmatrix} \begin{pmatrix} b_{11} & b_{12} \\ b_{21} & b_{22} \\ b_{31} & b_{32} \end{pmatrix} = \begin{pmatrix} a_{11} b_{11} + a_{12} b_{21} + a_{13} b_{31} & a_{11} b_{12} + a_{12} b_{22} + a_{13} b_{32} \\ a_{21} b_{11} + a_{22} b_{21} + a_{23} b_{31} & a_{21} b_{12} + a_{22} b_{22} + a_{23} b_{32} \end{pmatrix} \end{gathered} (a11a21a12a22a13a23)b11b21b31b12b22b32=(a11b11+a12b21+a13b31a21b11+a22b21+a23b31a11b12+a12b22+a13b32a21b12+a22b22+a23b32)

必须注意: 只有当第一个矩阵(左矩阵)的列数等于第二个矩阵(右矩阵)的行数时,两个矩阵才能相乘。

在矩阵乘法中必须注意矩阵相乘的顺序。矩阵的乘法不满足交换律,即在一般情况下,AB≠BA。

矩阵的乘法不满足交换律,但是满足结合律,这是矩阵快速幂的关键。

矩阵快速幂

在计算一些有递推公式的问题时,我们可以通过矩阵乘法来计算。

例如斐波那契数列。
f n = f n − 1 + f n − 2 f_n = f_{n-1} + f_{n-2} fn=fn1+fn2
我们可以构造出一个矩阵T

使得
( f n − 1 f n )   T = ( f n f n + 1 ) \begin{gathered} \begin{pmatrix} f_{n-1} & f_n \end{pmatrix} \ T= \begin{pmatrix} f_{n} & f_{n + 1} \end{pmatrix} \end{gathered} (fn1fn) T=(fnfn+1)

T = ( 0 1 1 1 ) T=\begin{gathered} \begin{pmatrix} 0 & 1 \\ 1 & 1 \end{pmatrix} \end{gathered} T=(0111)

当我们想求斐波那契数列的某一位时,就可以将矩阵乘上n个T

由于矩阵乘法满足结合律,我们计算时可以先利用快速幂的思想来计算矩阵T的乘积。

快速幂的简单理解

#include <iostream>
#include <cstring>

using namespace std;

const int N = 2;

void mul(int c[], int a[], int b[][N])
{
    int temp[N] = {0};
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            temp[i] += a[j] * b[j][i];
        }
    }
    memcpy(c, temp, sizeof temp);
}

void mul(int c[][N], int a[][N], int b[][N])
{
    int temp[N][N] = {0};
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            for (int k = 0; k < N; k++)
            {
                temp[i][j] += a[i][k] * b[k][j];
            }
        }
    }
    memcpy(c, temp, sizeof temp);
}

int main()
{
    int f[2] = {1, 1};
    int a[N][N] = {
        {0, 1},
        {1, 1}
    };
    int n;
    cin >> n;
    n--;
    while (n)
    {
        if (n & 1) mul(f, f, a);
        mul(a, a, a);
        n >>= 1;
    }
    cout << f[0] << endl;
    return 0;
}

下代码为求解斐波那契数列的前n项和

#include <iostream>
#include <cstring>

using namespace std;                                                                                                                                                                       

typedef long long ll;

const int N = 3;

int n, m;

void mul(int c[], int a[], int b[][N])                                                                                                                                                     
{                                                                                                                                                                                          
    int temp[N] = {0};                                                                                                                                                                     
    for (int i = 0; i < N; i++)                                                                                                                                                            
    {                                                                                                                                                                                      
        for (int j = 0; j < N; j++)                                                                                                                                                        
        {                                                                                                                                                                                  
            temp[i] = (temp[i] + (ll) a[j] * b[j][i]) % m;
        }                                                                                                                                                                                  
    }
    memcpy(c, temp, sizeof temp);
}

void mul(int c[][N], int a[][N], int b[][N])
{
    int temp[N][N] = {0};
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            for (int k = 0; k < N; k++)
            {
                temp[i][j] = (temp[i][j] + (ll) a[i][k] * b[k][j]) % m;
            }
        }
    }
    memcpy(c, temp, sizeof temp);
}

int main()
{
    int f[3] = {1, 1, 1};
    int a[N][N] = {
        {0, 1, 0},
        {1, 1, 1},
        {0, 0, 1}
    };
    cin >> n >> m;
    n--;
    while (n)
    {
        if (n & 1) mul(f, f, a);
        mul(a, a, a);
        n >>= 1;
    }
    cout << f[2] << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值