矩阵乘法

矩阵乘法

前言

矩阵乘法属于数论中的知识点,其实也就是新的概念,就像向量的运算一样,接受了之后就好了,当然可能会容易忘记,所以还是要多用多练。

基本概念

  • 矩阵是一个按照长方阵列排列的复数或实数集合。

形如

\[A = \begin{bmatrix} a_{1,1} & a_{1,2} & \cdots & a_{1,n} \\ a_{2,1} & a_{2,2} & \cdots & a_{2,n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m,1} & a_{m,2} & \cdots & a_{m,n} \end{bmatrix} \]

矩阵就是多个数的集合。其中行数和列数相等(即 \(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} = \sum_{k = 1}^{n} a_{i,k} b_{k,j} \text{ , ($1 \le i \le m$, $1 \le j \le p$).} \]

展开来:\(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 矩阵乘法

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 【模板】矩阵快速幂

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 矩阵加速(数列)

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\)

\[base= \begin{bmatrix} 1 & 0 & 1\\ 1 & 0 & 0 \\ 0 & 1 & 0 \\ \end{bmatrix} \]

可以看出 \(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 斐波那契数列

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= \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \]

\(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。

posted @ 2024-01-05 21:59  zhouruoheng  阅读(30)  评论(0编辑  收藏  举报