矩阵基础(未完结)


矩阵基础

矩阵是线性代数中一个非常重要的内容,也是 NOIP 的考点之一。

定义

对于矩阵 \(A\),主对角线是指 \(A_{i,i}\) 的元素。

0元:所有位置均为 0 的矩阵。

1元(单位矩阵):主对角线上为 1,其余位置为 0 的矩阵。

单位矩阵之所以是主对角线,是因为一个矩阵在乘上单位矩阵之后是它本身,这就符合我们在学数的基本运算时,一个数乘它本身等于它本身。

实现代码:

struct mat//定义一个矩阵
{
    int v[maxn][maxn];//v[i][j]表示矩阵第 i 行第 j 列的元素
    int n;
    mat(){memset(v,0,sizeof(v));}//初始化一个空矩阵为0元
    mat(int N,int one=0)//初始化矩阵的大小并定义1元。
    {
        n=N;memset(v,0,sizeof(v));
        if(one)for(int i=1;i<=n;i++)v[i][i]=1;//如果定义了单位矩阵,则将主对角线初始化为1。
    }
};

运算

加法/减法

矩阵的加法/减法定义为把两个矩阵对应位置上的数相加减,即 \(C=A \pm B \Leftrightarrow \forall i \in [1,n],\forall j \in [1,m],C_{i,j} = A_{i,j} \pm B_{i,j}\),其中 \(A,B,C\) 都是 \(n \times m\) 矩阵。

乘法

\(A\)\(n \times m\) 矩阵,\(B\)\(m \times p\) 矩阵,则 \(C=A \times B\)\(n \times p\) 矩阵,并且对于 \(\forall i \in [1,n],\forall j \in [1,p]\)

\[C_{i,j}=\sum \limits_{k=1}^{m} A_{i,k} \times B_{k,j} \]

条件:参与矩阵运算的第一个矩阵的列数必须等于第二个矩阵的行数

所以结果矩阵 \(C\) 的第 \(i\) 行第 \(j\) 列的数,是由矩阵 \(A\) 的第 \(i\) 行的 \(m\) 个数与矩阵 \(B\) 的第 \(j\) 列的 \(m\) 个数分别相乘再相加得到。

代码实现:

mat operator*(mat A,mat B)//利用重载运算符重载矩阵乘法
{
    mat C=mat(A.n);//C表示 A*B 的结果,由于这里A和B都是方阵,所以结果矩阵的大小和A的大小相同。
    //注意:如果A和B并非方阵,则不能这么定义,而是应该定义为A的行数乘B的列数。
    for(int i=1;i<=C.n;i++)
    for(int j=1;j<=C.n;j++)
    for(int k=1;k<=C.n;k++)
        (C.v[i][j]+=A.v[i][k]*B.v[k][j])%=mod;    
    return C;      
}

运算律

矩阵乘法不满足交换律,因为对于矩阵 \(A\)\(B\)\(p \ne n\)

满足结合律,即 \((A \times B) \times C=A \times (B \times C)\)

满足分配律,即 \((A+B) \times C=A \times C + B \times C\)

我们可以利用矩阵的结合律,来实现矩阵快速幂。

矩阵快速幂

问题模型:对于一个矩阵 \(A\),求它的 \(k\) 次幂的结果,即 \(A^k\)

首先很容易想到一个 \(O(k)\) 的做法——暴力模拟。

是否有优化做法呢?

联想到我们学习快速幂的做法,能否同样运用到矩阵中去呢?

答案是肯定的。

我们可以发现,矩阵中的快速幂其实和数中的快速幂完全一样。因为矩阵的性质和数的性质具有相似性。

实现代码:

int qpow(mat A,int T)
{
    mat ret=mat(A.n,1);//在普通快速幂中我们是初始化为1,这里初始化为单位矩阵。
    while(T)
    {
        if(T&1)ret=ret*A;
        A=A*A;T>>=1;
    }
    return ret;
}

十进制矩阵快速幂

和普通的十进制快速幂实际上也是一样的(已经通过倍增优化):

mat qpow(mat A,string T)
{
    mat ret=mat(A.n,1),t[20];
    t[1]=A;for(int i=2;i<=9;i++)t[i]=t[i-1]*A;//预处理出A^2到A^9,避免时间复杂度爆炸
    int l=T.size()-1;
    for(int i=0;i<=l;i++)
    {
        if(i)//ret^10,这里通过倍增优化。
        {
            mat x=ret*ret;//x=ret^2
            mat y=x*x;//y=ret^4
            mat z=y*y;//z=ret^8
            ret=z*x;//ret'=(ret^8)*(ret^2)=z*x;
        }
        int now=T[i]-'0';
        if(now)ret=ret*t[now];//注意特判now!=0
    }
    return ret;
}

应用

矩阵加速递推

P1962 斐波那契数列

总结/题解

P1397 [NOI2013] 矩阵游戏
总结/题解

P3758 [TJOI2017]可乐


感觉矩阵这块,知识点很少,但是题做起来却没有做数论那么顺手。其实是我太菜了

所以主要的总结都放在题目总结里面了。知识点总结相对较少。

To be continued……