欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

线性代数随笔

程序员文章站 2022-07-12 14:50:53
...

线性代数学习笔记

矩阵(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)$

这就很舒服

但是这个有什么用呢?

例题一

a[1]=a[2]=a[3]=1

a[x]=a[x-3]+a[x-1] (x>3)

求a数列的第n项对1000000007(10^9+7)取余的值。

第一眼看到这个题

?

这不是来送分的么

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

对于100%的数据 T<=100,n<=2*10^9;

笑容逐渐凝固

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

对于一个数列$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}
$$
下面就是简单的矩阵快速幂了