矩阵快速幂

定义

什么是矩阵运算呢?

在理解这个问题前,我们先要知道什么是矩阵

百度百科给的定义如下

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

复数实数什么的我们先不管,总之,矩阵就是一堆数,按照矩形排列形成的集合

那么,我们所需要记录的也就是它的长、宽以及矩阵中存储的元素

特殊的,长宽相等的矩阵我们定义它为方阵

当两个矩阵的长宽相等时,我们认为这两个矩阵为同型矩形

基本运算

矩阵的运算我们可以类比实数的运算来理解

在实数运算中,一般由进行运算的实数和运算符组成,运算符决定了运算类型

那么同样的,矩阵运算也是如此

加法运算

首先,我们来看加法运算

两个矩阵进行一般的加法运算的前提是两个矩阵为同型矩阵

我们只需要将对应位置的元素相加即可,如下图

在矩阵的加法运算中,满足交换律和结合律,也就是

A+B=B+AA+B=B+A

(A+B)+C=A+(B+C)(A+B)+C=A+(B+C)

也许有人想问了,如果我想让两个非同型矩形进行相加可不可以实现呢?

答案是可以的,这种运算是被支持的,我们称这种运算为直和

减法运算

在实数运算中,减法为加法的逆运算,同样的,在矩阵运算中也是如此,如下图

数乘

在实数运算中我们并没有数乘这种运算(毕竟本身就是数,直接叫乘法了)

所以在数乘运算中,我们类比向量来进行理解

在数乘向量运算中,只需要将向量中的每个元素乘上那个数就可以了

数乘矩阵也是如此,如图

数乘矩阵运算中,满足如下运算律

(λμ)A=λ(μA)(λμ)A=λ(μA)

(λ+μ)A=λA+μA(λ+μ)A=λA+μA

λ(A+B)=λA+λBλ(A+B)=λA+λB

矩阵乘法(矩阵乘矩阵)

在向量乘向量的运算中,是将每个元素与它对应的元素相乘,求所有乘积之和

那么矩阵乘矩阵是不是就是两个同型矩阵的对应元素相乘呢?

图样图森破

两个矩阵相乘的前提是前一个矩阵的列数等于后一个矩阵的行数

举个栗子,AA为n∗kn∗k矩阵,BB为k∗mk∗m矩阵,CC为m∗nm∗n矩阵,那么AA可以与BB相乘,BB可以与CC相乘,CC可以与AA相乘,其他均不成立

我们知道了什么情况下两个矩阵可以相乘,那么他们怎么相乘呢?不讲每个对应位置相乘还能怎么乘呢?

设AA为n∗kn∗k矩阵,BB为k∗mk∗m矩阵,那么它们的乘积CC则为一个n∗mn∗m矩阵

Ci,j=∑r=1kAi,r∗Br,jCi,j​=∑r=1k​Ai,r​∗Br,j​

是不是不太好理解,没关系看看图就知道了

在矩阵乘法中满足以下运算律:

(AB)C=a(BC)(AB)C=a(BC)

(A+B)C=AC+BC(A+B)C=AC+BC

C(A+B)=CA+CBC(A+B)=CA+CB

在普通的乘法中,一个数乘1还是等于它本身,在矩阵乘法中也有这么一个“1”,它就是单位矩阵

不同于普通乘法中的单位1,对于不同矩阵他们的单位矩阵大小是不同的

对于n∗mn∗m的矩阵,它的单位矩阵大小为m∗mm∗m,对于m∗nm∗n的矩阵,它的单位矩阵大小为n∗nn∗n

也就是说单位矩阵都是正方形的,这是因为只有正方形的矩阵能保证结果和前一个矩阵形状相同

单位矩阵的元素非0即1,从左上角到右下角的对角线上元素皆为1,其他皆为0


了解了这么多,我们开始看题,矩阵快速幂,由于矩阵乘法满足结合律,所以我们只需要把它按照一般的快速幂打,再重载一下运算符就可以了,好了我们直接放代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc() getchar()
#define maxn 105
#define mo 1000000007
using namespace std;

inline ll read(){
	ll a=0;int f=0;char p=gc();
	while(!isdigit(p)){f|=p=='-';p=gc();}
	while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
	return f?-a:a;
}
int n;

struct ahaha{
	ll a[maxn][maxn];     //一定要用long long存矩阵,否则在过程中会爆掉
	ahaha(){
		memset(a,0,sizeof a);
	}
	inline void build(){     //建造单位矩阵
		for(int i=1;i<=n;++i)a[i][i]=1;
	}
}a;
ahaha operator *(const ahaha &x,const ahaha &y){     //重载运算符
	ahaha z;
	for(int k=1;k<=n;++k)
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mo)%mo;
	return z;
}

ll k;
inline void init(){
	n=read();k=read();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			a.a[i][j]=read();
}

int main(){
	init();
	ahaha ans;ans.build();
	do{     //递推快速幂,与普通的递推快速幂无异,但*不能缩写为*=
		if(k&1)ans=ans*a;
		a=a*a;k>>=1;
	}while(k);
	for(int i=1;i<=n;putchar('\n'),++i)
		for(int j=1;j<=n;++j)
			printf("%d ",ans.a[i][j]);
	return 0;
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值