矩阵乘法
矩阵乘法
前言
矩阵乘法属于数论中的知识点,其实也就是新的概念,就像向量的运算一样,接受了之后就好了,当然可能会容易忘记,所以还是要多用多练。
基本概念
- 矩阵是一个按照长方阵列排列的复数或实数集合。
形如
矩阵就是多个数的集合。其中行数和列数相等(即 \(m=n\) )的矩阵叫做方阵。
当两个矩阵的行数和列数分别相等时,这两个矩阵叫做同型矩形。
定义 \(A^0\) 为单位矩阵 \(I = \begin{bmatrix} 1 & 0 & \cdots & 0 \\ 0 & 1 & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & 1 \end{bmatrix}\)。
矩阵乘法
- 前提:前一个矩阵的列数等于后一个矩阵的行数。
两个大小分别为 \(m \times n\) 和 \(n \times p\) 的矩阵 \(A, B\) 相乘的结果为一个大小为 \(m \times p\) 的矩阵。将结果矩阵记作 \(C\),则
展开来:\(c_{i,j}=a_{i,1} \times b_{1 j}+a_{i,2} \times b_{2,j}+ \dots +a_{i,k} \times b_{k,j}\)
如:
\(A = \begin{bmatrix} 1 & 2 & 3 \\ 1 & 4 & 2 \\ \end{bmatrix} \text{ , } B = \begin{bmatrix} 3 & 2 \\ 5 & 4 \\ 1 & 4 \\ \end{bmatrix} \text{ , } C=A*B=\begin{bmatrix} 1*3+2*5+3*1 & 1*2+2*4+3*4 \\ 1*3+4*5+2*1 & 1*2+4*4+2*4 \\ \end{bmatrix}= \begin{bmatrix} 16 & 22 \\ 25 & 26 \\ \end{bmatrix}\)
在计算时,我们要把行和列当做整体:
\(A = \begin{bmatrix} 行1 \\ 行2 \\ \end{bmatrix} \text{ , } B = \begin{bmatrix} 列1 & 列2 \end{bmatrix} \text{ , } C=A*B= \begin{bmatrix} 行1*列1 & 行1*列2 \\ 行2*列1 & 行2*列2 \\ \end{bmatrix}\)
行 * 列,为行和列对应位置元素的乘积之和。
此外,对于单位矩阵 \(I\) 而言,有 \(A*I=A\)
矩阵乘法满足结合律和分配律,但不满足交换律(元素位置会不同):
- \((A B) C = A (B C)\)
- \((A+B) C = A C+B C\)
- \(AB \neq BA\)
B2105 矩阵乘法
分析
基础题,按照定义来做,理解概念即可。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=105;
int n,m,k,a[N][N],b[N][N],c[N][N];
int main ()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=m;i++)
for(int j=1;j<=k;j++)
cin>>b[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
for(int l=1;l<=m;l++)
c[i][j]+=a[i][l]*b[l][j];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=k;j++) cout<<c[i][j]<<" ";
cout<<"\n";
}
return 0;
}
P3390 【模板】矩阵快速幂
分析
矩阵快速幂=矩阵乘法+快速幂。
由于矩阵乘法满足结合律,所以只需要将快速幂里的乘法改为矩阵乘法就可以了。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=105,mod=1e9+7;
int n;
typedef vector<ll> vec;
typedef vector<vec> mat;//matrix
mat mul(mat a,mat b)
{
mat ans(a.size(),vec(b[0].size()));//行数为a的行数,列数为b的列数
for(int i=0;i<a.size();i++)
for(int j=0;j<b[0].size();j++)
{
for(int k=0;k<b[0].size();k++) ans[i][j]+=a[i][k]*b[k][j]%mod;
ans[i][j]%=mod;
}
return ans;
}
mat qmod(mat a,ll k)
{
mat ans(a.size(),vec(a.size()));
for(int i=0;i<n;i++) ans[i][i]=1;//初始化为单位矩阵
while(k)
{
if(k&1) ans=mul(ans,a);
a=mul(a,a);
k>>=1;
}
return ans;
}
int main()
{
ll k;
cin>>n>>k;
mat a(n,vec(n));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>a[i][j];
mat ans=qmod(a,k);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++) cout<<ans[i][j]%mod<<" ";
cout<<"\n";
}
return 0;
}
P1939 矩阵加速(数列)
分析
\(a_x\) 是由 \(a_{x-1}\) 和 \(a_{x-3}\) 推导来的。因此我们要求一个矩阵 \(base\) 使得 $\begin{bmatrix} a_{x-1} & a_{x-2} & a_{x-3} \end{bmatrix} \times base = \begin{bmatrix} a_{x} & a_{x-1} & a_{x-2} \end{bmatrix} $。这是基本套路,因为我们要利用 \(base\) 矩阵不断向后推导得到答案。则有:
- \(a_{x}=a_{x-1} \times 1+a_{x-2} \times 0+a_{x-3} \times 1\)
- \(a_{x-1}=a_{x-1} \times 1+a_{x-2} \times 0+a_{x-3} \times 0\)
- \(a_{x-2}=a_{x-1} \times 0+a_{x-2} \times 1+a_{x-3} \times 0\)
可以看出 \(a_{x}\) 是根据公式推导的,而 \(a_{x-1}\) 和 \(a_{x-2}\) 是直接继承的。
显然,\(base^{x-1}\) 的第一行第一列元素就是 \(a_x\),用矩阵快速幂就可以了。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=105,mod=1e9+7;
int n;
typedef vector<ll> vec;
typedef vector<vec> mat;//matrix
mat mul(mat a,mat b)
{
mat ans(a.size(),vec(b[0].size()));//行数为a的行数,列数为b的列数
for(int i=0;i<a.size();i++)
for(int j=0;j<b[0].size();j++)
{
for(int k=0;k<b[0].size();k++) ans[i][j]+=a[i][k]*b[k][j]%mod;
ans[i][j]%=mod;
}
return ans;
}
mat qmod(mat a,ll k)
{
mat ans(a.size(),vec(a.size()));
for(int i=0;i<n;i++) ans[i][i]=1;
while(k)
{
if(k&1) ans=mul(ans,a);
a=mul(a,a);
k>>=1;
}
return ans;
}
int main()
{
ll k;
int t;
n=3;
cin>>t;
mat a(n,vec(n));
while(t--)
{
cin>>k;
if(k<=3)
{
cout<<1<<"\n";
continue;
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=0;
a[0][0]=a[0][2]=a[1][0]=a[2][1]=1;
mat ans=qmod(a,k-1);
cout<<ans[0][0]<<"\n";
}
return 0;
}
P1962 斐波那契数列
分析
同P1939 矩阵加速(数列),求矩阵 \(base\) 使得 $\begin{bmatrix} F_{x-1} & F_{x-2} \end{bmatrix} \times base = \begin{bmatrix} F_{x} & F_{x-1} \end{bmatrix} $,则:
- \(F_{x}=F_{x-1} \times 1+F_{x-2} \times 1\)
- \(F_{x-1}=F_{x-1} \times 1+F_{x-2} \times 0\)
\(base^{x-1}\) 的第一行第一列元素就是 \(F_x\)
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=105,mod=1e9+7;
int n;
typedef vector<ll> vec;
typedef vector<vec> mat;//matrix
mat mul(mat a,mat b)
{
mat ans(a.size(),vec(b[0].size()));//行数为a的行数,列数为b的列数
for(int i=0;i<a.size();i++)
for(int j=0;j<b[0].size();j++)
{
for(int k=0;k<b[0].size();k++) ans[i][j]+=a[i][k]*b[k][j]%mod;
ans[i][j]%=mod;
}
return ans;
}
mat qmod(mat a,ll k)
{
mat ans(a.size(),vec(a.size()));
for(int i=0;i<n;i++) ans[i][i]=1;
while(k)
{
if(k&1) ans=mul(ans,a);
a=mul(a,a);
k>>=1;
}
return ans;
}
int main()
{
ll k;
n=2;
cin>>k;
mat a(n,vec(n));
if(k<=2)
{
cout<<1<<"\n";
return 0;
}
a[0][0]=a[0][1]=a[1][0]=1;
mat ans=qmod(a,k-1);
cout<<ans[0][0]<<"\n";
return 0;
}
写起来挺累的 qwq。