矩阵乘法、矩阵快速幂

一定要看好乘的顺序!!!!!横的在前,竖的在后!

矩阵乘法和矩阵快速幂本身简单,但是构造出矩阵递推式的过程比较考验智慧。

1 矩阵乘法

1.定义

若矩阵A的大小为n×m,矩阵B的大小为m×p,则两个矩阵可以做乘法,得到的矩阵C的大小为n×p

A=[a11a12a13a21a22a23] B=[b11b12b21b22b31b32] C=A×B=[a11×b11+a12×b21+a13×b31a11×b12+a12×b22+a13×b32a21×b11+a22×b21+a23×b31a21×b12+a22×b22+a23×b32]

注意:只有矩阵A的列数等于矩阵B的行数时,两个矩阵才能相乘。

2.代码实现

int a[N][N],b[N][N],c[N][N];
signed main()
{
	#ifdef LOCAL
	freopen("in.in","r",stdin);
	#endif
	int n = read(),m = read();
	for(int i{1};i<=n;i++)
	for(int j{1};j<=m;j++) a[i][j] = read();
	int k = read();
	for(int i{1};i<=m;i++)
	for(int j{1};j<=k;j++) b[i][j] = read();
	for(int i{1};i<=n;i++)
		for(int j{1};j<=m;j++)
			for(int l{1};l<=k;l++)
				c[i][l] += a[i][j] * b[j][l]; 
	for(int i{1};i<=n;i++)
	{
		for(int j{1};j<=k;j++)
			writek(c[i][j]);
		putchar(10);
	}

	exit(0);
}

2 矩阵快速幂

模版

注意在给 res 的初值赋成单位矩阵 I=[100010001]

const int N = 1e2+5;
int n;
const int MOD = 1e9+7;
struct MATRIX
{
	int a[N][N]{};
	void build(){for(int i{1};i<=n;i++) a[i][i] = 1;}
	MATRIX operator *(const MATRIX md)
	{
		MATRIX as;
		for(int i{1};i<=n;i++)
			for(int j{1};j<=n;j++)
				for(int k{1};k<=n;k++)
					(as.a[i][k] += a[i][j] * md.a[j][k] % MOD ) %= MOD;
		return as;
	}
}mt;
inline MATRIX qp(MATRIX a,int b)
{
	MATRIX ans;
	ans.build();
	while(b)
	{
		if(b&1) ans = ans * a;
		a = a * a;
		b>>=1;
	}
	return ans;
 } 
signed main()
{
	#ifdef LOCAL
	freopen("in.in","r",stdin);
	#endif
	n = read();
	int k = read();
	for(int i{1};i<=n;i++)
	for(int j{1};j<=n;j++) mt.a[i][j] = read();
	MATRIX ans = qp(mt,k);
	for(int i{1};i<=n;i++)
	{
		for(int j{1};j<=n;j++) writek(ans.a[i][j]);
		putchar(10);
	}
	

Fibonacci第n项

题目描述:计算斐波那契数列第n项的后m位。

解析:

斐波那契数列的递推方程试可以写成矩阵的形式:

[f[n]f[n1]]=[1110]×[f[n1]f[n2]]

那么:

[f[n]f[n1]]=[1110]×[f[n1]f[n2]]=[1110]×[1110]×[f[n2]f[n3]]=[1110]n1×[f[1]f[0]]

于是,我们只需要类比普通的快速幂计算矩阵

[1110]

的快速幂即可。

Fibonacci前n项和

题目描述:

dn的前n项和Snmodm

解析:

考虑递推关系式:s[n]=s[n1]+f[n],写成矩阵形式:

[s[n]f[n+1]f[n]]=[110011010]×[s[n1]f[n]f[n1]]

所以:

[s[n]f[n+1]f[n]]=[110011010]n1×[s[1]f[2]f[1]]

佳佳的Fibonacci

题目描述:

T(n)=f1+2f2+3f3++nfn,求T(n)modm

解析:

递推关系式的矩阵中不能出现变量n,所以要先对递推关系式变形成我们可以处理的情况。

Tn=f1+2f2+3f3++nfn=n×SnSn1Sn2Sn3S1=n×Sni=1n1Si

i=1n1Si=S1+S2+S3++Sn1=f1+(f1+f2)++(f1+f2+f3++fn1)=(n1)f1+(n2)f2+(n3)f3++fn

Pn=i=1n1Si,则: Tn=n×SnPn

我们不需要递推Tn,只需要递推PnSn,再直接计算得到Tn

因为Pn=Pn1+Sn1,所以:

[PnSnfn+1fn]=[1100011000110010]×[Pn1Sn1fnfn1]

[UVA10870] Recurrences

考虑矩阵加速递推。

Fn=[fnfn+1fn+2fn+d1],容易有 Fn=[fnfn+1fn+2fn+d1]=[fn1fnfn+1fn+d2]×[000ad100ad1010ad2000a1]=[fn2fn1fnfn+d3]×[000ad100ad1010ad2000a1]2==[f1f2f3fd]×[000ad100ad1010ad2000a1]n1=F1×[000ad100ad1010ad2000a1]n1

接着矩阵快速幂处理即可。


int MOD;
int d,n,m;
const int N = 20;
int b[N],f[N];
struct MATRIX
{
	int a[N][N]{};
	void build()
	{
		for(int i{1};i<=d+1;i++) a[i][i] = 1;
	}
	void build2()
	{
		for(int i{1};i<=d+1;i++)
			a[1][i] = f[d+2-i];
	}
	void build3()
	{
		for(int i{1};i<=d;i++)
			a[i][1] = b[i];
		for(int i{2};i<=d+1;i++)
			a[i-1][i] = 1;
	}
	void print()
	{
		for(int i{1};i<=d+1;i++)
		{
			for(int j{1};j<=d+1;j++) writek(a[i][j]);
			putchar(10);
		}
	}
	MATRIX operator *(const MATRIX md)
	{
		MATRIX as;
		for(int i{1};i<=d+1;i++)
			for(int j{1};j<=d+1;j++)
				for(int k{1};k<=d+1;k++)
					(as.a[i][j] += a[i][k] * md.a[k][j] % MOD) %= MOD;
		return as;
	}
	
};
inline MATRIX qp(MATRIX aa,int b)
{
	MATRIX ans;
	ans.build();
	while(b)
	{
		if(b&1) ans = ans * aa;
		aa = aa * aa;
		b>>=1;
	}
	return ans;
 } 
signed main()
{
	#ifdef LOCAL
	freopen("in.in","r",stdin);
	#endif
	while(true)
	{
		d = read(),n = read(),MOD = read();
		for(int i{1};i<=d;i++) b[i] = read();
		for(int i{1};i<=d;i++) f[i] = read();
		if(!d && !n && !MOD) break;
		if(n<=d) {writeln(f[n]);continue;}
		f[d+1] = 0;
		for(int i{1};i<=d;i++)(f[d+1] += b[i]*f[d-i+1]) %= MOD;
		MATRIX ori;
		ori.build2();
		MATRIX mt;
		mt.build3();
		mt = qp(mt,n-d-1);
		ori = ori * mt;
		writeln(ori.a[1][1]);
	}
	
	exit(0);
}

递推中存在常数的处理

1.f(n)=a×f(n1)+b×f(n2)+c

[fnfn1c]=[ab1100001]×[fn1fn2c]

2.f(n)=cnf(n1)

[fncn]=[1c0c]×[fn1cn1]

矩阵幂求和

题目描述:

给定一个矩阵,求S=A+A2+A3++Ak,求S中的每个数对P取模的结果。

解析:

法一:递归

对式子进行变形,比如:A+A1+A2+A3+A4+A5+A6可以变形为A+A1+A2+A3+A3×(A+A2+A3)=(A3+1)(A+A2+A3),所以这个式子可以递归。如果k为偶数直接递归即可;如果k为奇数,递归计算Ak1,之后单独计算Ak

法二:分块矩阵

我们尝试使用

[SkAk]

[Sk1Ak1]

建立关系:

[SkSk]=[1A0A]×[Sk1Ak1]

我们会发现,这里面是矩阵包含着矩阵,所以这个矩阵的长度为 A的长度乘 2,同时下面的 1也为单位矩阵,0 也是一个矩阵,长度都为 A 的长度。我们求新矩阵的 n1次方,就可以得到Sk

图上路径方案

题目描述:

给定一个有向图的邻接矩阵 S,问从点 a 恰好走 K 步(允许重复经过边)到达 b 点的方案数模10007 的值。

解析:

如下图:

在图的邻接矩阵中,两点之间有连边用1表示,没有用0表示。

[011111100]

换个角度来想,在邻接矩阵A中,aij正好表示从点i到点j走一步的方案数,我们尝试将矩阵乘起来,变成A2。 在A2中,A112=a11×a11+a12×a21+a13×a31。在这个式子中,aikakj都为1,才能对最终的答案贡献1,所以Aijs=Aiks1+akj表示i到j走s步,可以是i到k走s-1步的基础上再走kj这条边,也就是多走了1步,所以乘一次邻接矩阵,相当于多走一步。所以本题我们直接对邻接矩阵做一个 k 的快速幂即可。

[USACO07NOV] Cow Relays G

题目描述:

给定一张T条边的无向连通图,求S到E经过M条边的最短路。

解析:

我们可以通过动态规划来解决此题。令f[i][j]表示达到i经过j条边的最短距离,那么转移方程如下:

f[i][j]=min(f[k][j1]+G[k][i])(1<=k<=N)

其中N为总的点数,如果k和i之间有边相连,则G[k][i]为边权,否则为正无穷。

上述dp方程时间复杂度为O(N2M),显然会T。 回顾矩阵乘法在图论里的应用式子:

C[i][j]=k=1pA[i][k]×B[k][j]

由于矩阵乘法满足分配律和结合律(不满足交换律),所以我们可以通过矩阵快速幂的方法来加速。于是:

C[i][j]=min(A[i][k]+B[k][j])(1<=k<=p)

例题7:[POJ 3734]Blocks

题目描述:

n个 blocks,让你用红,蓝,绿,黄四种颜色染上色,求红色和绿色的 block 都是偶数个的方案有多少个。

解析:

首先,令

dp[i][0] 表示当涂了前 i 个 blocks 之后,红色和绿色都是偶数个的方案数。

dp[i][1] 表示当涂了前 i 个 blocks 之后,红色和绿色只有一个是偶数个的方案个数。

dp[i][2] 表示当涂了前 i 个blocks之后,红色和绿色都不是偶数个的方案个数。

得出状态转移方程:

dp[i+1][0]=2×dp[i][0]+dp[i][1]

dp[i+1][1]=2×dp[i][0]+2×dp[i][1]+2×dp[i][2]

dp[i+1][2]=dp[i][1]+2×dp[i][2]

由于n<=1e9所以O(n)的dp是不行的,需要矩阵快速幂优化。

[A(n)B(n)C(n)]=[210222012]×[A(n1)B(n1)C(n1)][A(n)B(n)C(n)]=[210222012]n×[A(0)B(0)C(0)]

[SCOI 2009] 迷路

题目描述:

该有向图有n个结点,从1到n编号。Windy从1出发,必须恰好在t时刻到达n。求有多少种不同的路径,答案对2009取模。

解析:

首先,如果题目中的每一条边只用0和1表示并且用邻接矩阵A来存这张图,那么在矩阵At中,Aijt表示由i到j经过t条边的情况总数。 但这道题这么做显然不行,因为我们所有的推论都建立在边权为1的情况上。

虽然我们不能直接使用我们的结论,但最大边权是9,n也不超过10,不算大。所以我们可以采用拆点:把一个点拆成多个点。

先来拆一个边权不超过2的图:

可得矩阵:

[0221]

将其拆点:

将1.1看成结点1;1.2看成结点2;2.1看成结点3;2.2看成结点4,可得新矩阵:

[0100001000111000]

将其平方:

[0010001110110100]

我们再对非零点进行分类,原先就有的1看成蓝色,后面通过自连得到的1看成红色:

posted @   WanGMiNgWeI  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示