矩阵乘法

矩阵乘法

前言

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

基本概念

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

形如

A=[a1,1a1,2a1,na2,1a2,2a2,nam,1am,2am,n]

矩阵就是多个数的集合。其中行数和列数相等(即 m=n )的矩阵叫做方阵。

当两个矩阵的行数和列数分别相等时,这两个矩阵叫做同型矩形。

定义 A0 为单位矩阵 I=[100010001]

矩阵乘法

  • 前提:前一个矩阵的列数等于后一个矩阵的行数。

两个大小分别为 m×nn×p 的矩阵 A,B 相乘的结果为一个大小为 m×p 的矩阵。将结果矩阵记作 C,则

ci,j=k=1nai,kbk,j , (1im1jp).

展开来:ci,j=ai,1×b1j+ai,2×b2,j++ai,k×bk,j

如:
A=[123142] , B=[325414] , C=AB=[13+25+3112+24+3413+45+2112+44+24]=[16222526]

在计算时,我们要把行和列当做整体:

A=[12] , B=[12] , C=AB=[11122122]

行 * 列,为行和列对应位置元素的乘积之和。

此外,对于单位矩阵 I 而言,有 AI=A

矩阵乘法满足结合律和分配律,但不满足交换律(元素位置会不同):

  • (AB)C=A(BC)
  • (A+B)C=AC+BC
  • ABBA

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

分析

ax 是由 ax1ax3 推导来的。因此我们要求一个矩阵 base 使得 [ax1ax2ax3]×base=[axax1ax2]。这是基本套路,因为我们要利用 base 矩阵不断向后推导得到答案。则有:

  • ax=ax1×1+ax2×0+ax3×1
  • ax1=ax1×1+ax2×0+ax3×0
  • ax2=ax1×0+ax2×1+ax3×0

base=[101100010]

可以看出 ax 是根据公式推导的,而 ax1ax2 是直接继承的。

显然,basex1 的第一行第一列元素就是 ax,用矩阵快速幂就可以了。

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 使得 [Fx1Fx2]×base=[FxFx1],则:

  • Fx=Fx1×1+Fx2×1
  • Fx1=Fx1×1+Fx2×0

base=[1110]

basex1 的第一行第一列元素就是 Fx

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 @   zhouruoheng  阅读(29)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示