线性代数学习笔记

矩阵(Matrix)

矩阵简介及矩阵加速

简介

通俗的来讲,把集合里的一些数填入到一个矩形中即得到一个矩阵

定义

由$m\times n$个数$a_{i,j}$排成的数表称为$m$行$n$列的矩阵简称$m\times n$矩阵。
$$
A=\begin{bmatrix}a_{1,1}&a_{1,2}&...&a_{1,n}\a_{2,1}&a_{2,2}&...&a_{2,n}\...&...&...&...\a_{m,1}&a_{m,2}&...&a_{m,n}\end{bmatrix}
$$
这$n\times m$个数称为矩阵$A$的元素,简称为元。。。(

有$m$行$n$列的矩阵也记作$A_{mn}$

特别的,两个$n,m$都相同的矩阵称为同型矩阵

$n=m$的矩阵称为$n$阶矩阵或者$n$阶方阵

基本运算

加法

$$
\begin{bmatrix}a_{1,1}&...&a_{1,n}\...&...&...\a_{m,1}&...&a_{m,n}\end{bmatrix}+\begin{bmatrix}b_{1,1}&...&b_{1,n}\...&...&...\b_{m,1}&...&b_{m,n}\end{bmatrix}=\begin{bmatrix}a_{1,1}+b_{1,1}&...&a_{1,n}+b_{1,n}\...&...&...\a_{m,1}+b_{m,1}&...&a_{m,n}+b_{m,n}\end{bmatrix}
$$

同时,矩阵的加法和实数的加法一样,满足交换律和结合律


$$
A+B=B+A
$$

$$
(A+B)+C=A+(B+C)
$$

应当注意,只有同型矩阵之间才可以进行加法

减法

在数集中,减法作为加法的逆运算

在矩阵中也是一样的
$$
\begin{bmatrix}a_{1,1}&...&a_{1,n}\...&...&...\a_{m,1}&...&a_{m,n}\end{bmatrix}-\begin{bmatrix}b_{1,1}&...&b_{1,n}\...&...&...\b_{m,1}&...&b_{m,n}\end{bmatrix}=\begin{bmatrix}a_{1,1}-b_{1,1}&...&a_{1,n}-b_{1,n}\...&...&...\a_{m,1}-b_{m,1}&...&a_{m,n}-b_{m,n}\end{bmatrix}
$$
它也满足在实数集上的规律

数乘

在矩阵中引入了数乘的概念,即为一个数乘一个矩阵
$$
\mu·\begin{bmatrix}a_{1,1}&...&a_{1,n}\...&...&...\a_{m,1}&...&a_{m,n}\end{bmatrix}=\begin{bmatrix}\mu· a_{1,1}&...&\mu· a_{1,n}\...&...&...\\mu· a_{m,1}&...&\mu· a_{m,n}\end{bmatrix}
$$
矩阵的数乘满足以下规律:
$$
\lambda(\mu A)=\mu(\lambda A)
$$

$$
\lambda(\mu A)=(\lambda\mu A)
$$

$$
(\lambda +\mu)A=\lambda A+\mu A
$$

$$
\lambda(A+B)=\lambda A+\lambda B
$$

乘法

两个矩阵的乘法仅当第一个矩阵$A$的列数和另一个矩阵$B$的行数相等时才能定义。

记作
$$
A_{mn} B_{np}=C_{mp}
$$
也作
$$
AB=C
$$
$C$的一个元素$c_{i,j}$的值为
$$
c_{i,j}=\sum_{k=1}^na_{i,k}\times b_{k,j}
$$
例如
$$
\begin{bmatrix}1 &0 &2\-1&3&1\end{bmatrix}\times\begin{bmatrix}3&1\2&1\1&0\end{bmatrix}=\begin{bmatrix}(1\times 3+0\times2+2\times1)&(1\times1+0\times1+2\times0)\(-1\times3+3\times2+1\times1)&(-1\times1+3\times1+1\times0)\end{bmatrix}=\begin{bmatrix}5&1\4&2\end{bmatrix}
$$
同时,矩阵的乘法满足以下运算律:

结合律:
$$
(AB)C=A(BC)
$$
左分配律:
$$
(A+B)C=AC+BC
$$
右分配律:
$$
C(A+B)=CA+CB
$$

矩阵加速

快速幂

这个还需要多说么?

int base=a,ans=1;
while(b>0){
    if(b&1){
        ans*=base
        ans%=c;
    }
    base*=base
    base%=c;
    b=b>>1;
}
return ans;

就是很简单的按位运算

所以我们对于一个矩阵的幂也可以这么来运算,于是时间复杂度从$O(n)$降到了$O(log_2n)$

但是这个有什么用呢?

例题一

第一眼看到这个题

?

这不是来送分的么

我一项一项去推不就好了???

所以现在就体现出矩阵加速的用处了

对于一个数列$f(n)=f(n-x)+f(n-y)+...$

我们可以构造出一个$k\times1$的矩阵表示当前的状态,即用$f(x),f(y)...$来表示我们当前已经知道的

然后我们再构造一个转移矩阵,使我们的原始矩阵乘上这个转移矩阵后可以变成一个新的矩阵,得到全新的$f(x)$,从而一步步的向前推进,得到答案

显而易见,由于我们需要用到$f(n-1)$和$f(n-3)$,所以我们需要保留住这两个状态,$f(n-3)$是由上个状态的$f(n-2)$继承过来的,所以我们也需要保留,所以原始矩阵要构造成这个样子
$$
\begin{bmatrix}f(3)\f(2)\f(1)\end{bmatrix}
$$
即为
$$
\begin{bmatrix}1\1\1\end{bmatrix}
$$
然后思考我们怎么由这个矩阵得到下一个矩阵

设我们当前矩阵为
$$
\begin{bmatrix}f(n-1)\f(n-2)\f(n-3)\end{bmatrix}
$$
我们希望得到的矩阵为
$$
\begin{bmatrix}f(n)\f(n-1)\f(n-2)\end{bmatrix}
$$
即为
$$
\begin{bmatrix}f(n-1)\times1+f(n-2)\times 0+f(n-3)\times1\f(n-1)\times1+f(n-2)\times0+f(n-3)\times0\f(n-1)\times0+f(n-2)\times1+f(n-3)\times0\end{bmatrix}
$$
显而易见我们的转移矩阵为
$$
\begin{bmatrix}1&0&1\1&0&0\0&1&0\end{bmatrix}
$$
由于我们原始矩阵的第一项为$f(3)$,所以我们只需要乘$n-3$次这个转移矩阵就可以得到了!

但是问题来了,这样不还是一个$O(n)$的算法么?

当然不是!想一下我们矩阵乘法的结合律

我们设原始矩阵为$A$,转移矩阵为$B$,那么我们最终答案的矩阵就是
$$
\underbrace{B(B(B(B(B(B(B...(B}_{n-3}A))))))
$$
根据矩阵乘法的结合律,这个式子可以简化为
$$
B^{n-3}A
$$
到了这里,我们就可以用矩阵快速幂来求出最终答案了!

$O(log_2n)$是真的快(

贴上我的巨丑无比的代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define mod 1000000007
using namespace std;
struct Ju{
    long long p[5][5];
    Ju operator *(const Ju &a)const{
        Ju c;
        for(long long i=1;i<=3;i++){
            for(long long j=1;j<=3;j++){
                c.p[i][j]=0;
            }
        }
        for(long long i=1;i<=3;i++){
            for(long long j=1;j<=3;j++){
                for(long long k=1;k<=3;k++){
                    c.p[i][j]+=(a.p[i][k]*p[k][j])%mod;
                    c.p[i][j]%=mod;
                }
            }
        }
        return c;
    }
}ans,base;
void build(){
    for(long long i=1;i<=3;i++){
        for(long long j=1;j<=3;j++){
            base.p[i][j]=0;
        }
    }
    base.p[1][1]=base.p[1][3]=base.p[2][1]=base.p[3][2]=1;
    ans.p[1][1]=ans.p[2][1]=ans.p[3][1]=1;
}
void qsm(long long p){
    while(p!=0){
        if(p&1){
            ans=ans*base;
        }
        base=base*base;
        p>>=1;
    }
}
long long T,n;
int main(){
    cin>>T;
    for(long long i=1;i<=T;i++){
        cin>>n;
        if(n<=3){
            printf("1\n");
            continue;
        }
        build();
        qsm(n-3);
        cout<<ans.p[1][1]<<endl;
    }
    return 0;
}
例题二

让你求斐波那契数列的第n项,数据范围是longlong级别的

很明显的矩阵加速

构造原始矩阵:
$$
\begin{bmatrix}f(2)\f(1)\end{bmatrix}=\begin{bmatrix}1\1\end{bmatrix}
$$
思考答案怎么由上一个状态转移过来
$$
\begin{bmatrix}f(n)\f(n-1)\end{bmatrix}=\begin{bmatrix}f(n-1)\times1+f(n-2)\times1\f(n-1)\times1+f(n-2)\times0\end{bmatrix}
$$
所以转移矩阵
$$
\begin{bmatrix}1&1\1&0\end{bmatrix}
$$
下面就是简单的矩阵快速幂了

02-13 02:26