矩阵的加减法和数乘为线性运算,均为逐个元素进行运算。
形式化地,即 A o p B = A i , j o p B i , j A\space op\space B=A_{i,j}\space op\space B_{i,j} A op B=Ai,j op Bi,j, o p op op 为 + / − +/- +/−。
矩阵乘法要求两个矩阵的行数和列数相等,设
A
A
A 为
P
×
M
P\times M
P×M 的矩阵,
B
B
B 为
M
×
Q
M\times Q
M×Q 的矩阵,则
C
=
A
×
B
,
C
i
,
j
=
∑
k
=
1
M
A
i
,
k
×
B
k
,
j
C=A\times B,C_{i,j}=\sum_{k=1}^{M}A_{i,k}\times B_{k,j}
C=A×B,Ci,j=∑k=1MAi,k×Bk,j。即矩阵
A
A
A 第
i
i
i 行
M
M
M 个数与矩阵
B
B
B 第
j
j
j 列
M
M
M 个数分别相乘再相加得到的,如下图。
为了方便进行运算,我们会把矩阵设为二维数组,放在结构体里面,并重载运算符。
这是我的矩阵加减乘法的模版。
struct matrix{
int a[N][N];
matrix(){memset(a,0,sizeof(a));}
matrix operator +(const matrix& T) const{
matrix res;
for(int i=1;i<N;i++)
for(int j=1;j<N;j++)
res.a[i][j]=(a[i][j]+T.a[i][j])%mod;
return res;
}
matrix operator -(const matrix& T) const{
matrix res;
for(int i=1;i<N;i++)
for(int j=1;j<N;j++)
res.a[i][j]=(a[i][j]-T.a[i][j])%mod;
return res;
}
matrix operator *(const matrix& T) const{
matrix res;//这个写法常数会小一些
for(int i=1;i<N;i++){
for(int k=1;k<N;k++){
int r=a[i][k];
for(int j=1;j<N;j++)
res.a[i][j]=(res.a[i][j]+1ll*r*T.a[k][j])%mod;
}
}
return res;
}
};
由于矩阵也有乘法,那自然也有矩阵的快速幂,写法与普通快速幂同理。
附洛谷矩阵快速幂模版代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define rd read()
const int N=110,mod=1e9+7;
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,k;
struct matrix{
int a[N][N];
matrix(){memset(a,0,sizeof(a));}
matrix operator +(const matrix& T) const{
matrix res;
for(int i=1;i<N;i++)
for(int j=1;j<N;j++)
res.a[i][j]=(a[i][j]+T.a[i][j])%mod;
return res;
}
matrix operator -(const matrix& T) const{
matrix res;
for(int i=1;i<N;i++)
for(int j=1;j<N;j++)
res.a[i][j]=(a[i][j]-T.a[i][j])%mod;
return res;
}
matrix operator *(const matrix& T) const{
matrix res;
for(int i=1;i<N;i++){
for(int k=1;k<N;k++){
int r=a[i][k];
for(int j=1;j<N;j++)
res.a[i][j]=(res.a[i][j]+1ll*r*T.a[k][j])%mod;
}
}
return res;
}
}M;
signed main(){
n=rd,k=rd;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) M.a[i][j]=rd;
matrix res;
for(int i=1;i<=n;i++) res.a[i][i]=1;//res要初始化为单位矩阵,即单位矩阵*M^K
while(k){
if(k&1) res=res*M;
M=M*M,k>>=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) cout<<res.a[i][j]<<" ";
cout<<"\n";
}
return 0;
}
而矩阵乘法的运用很多,最常用的便是加速递推,可以用其优化 dp(例如动态 dp)等等。最经典的便是斐波那契数列的应用,首先把原线性递推式转化为矩阵,然后用矩阵快速幂即可解决。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rd read()
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int mod=1e9+7;ll n;
struct matrix{
ll a[10][10];
matrix(){memset(a,0,sizeof(a));}
matrix operator *(const matrix& T)const{
matrix res;
for(int i=1;i<=2;i++){
for(int k=1;k<=2;k++){
ll r=a[i][k];
for(int j=1;j<=2;j++)
res.a[i][j]=(res.a[i][j]+1ll*r*T.a[k][j]%mod)%mod;
}
}
return res;
}
}bas,ans;
int main(){
n=rd;ll x=n-2;
if(n<=2){puts("1");return 0;}
ans.a[1][1]=ans.a[1][2]=1;
bas.a[1][1]=bas.a[1][2]=bas.a[2][1]=1;
while(x){
if(x&1) ans=ans*bas;
bas=bas*bas,x>>=1;
}
printf("%lld\n",ans.a[1][1]%mod);
return 0;
}
再来一道(P1939 矩阵加速(数列))
考虑 [ a i a i − 1 a i − 2 ] \begin{bmatrix} a_i& a_{i-1}&a_{i-2} \end{bmatrix} [aiai−1ai−2] 如何变为 [ a i + 1 a i a i − 1 ] \begin{bmatrix} a_{i+1}& a_{i}&a_{i-1} \end{bmatrix} [ai+1aiai−1],这道题非常显然。
[ a i + 1 a i a i − 1 ] × [ 1 1 0 0 0 1 1 0 0