矩阵乘法学习笔记

矩阵乘法

对于线性简单的 dp 可以使用矩阵快速幂加速转移,可以从 O(n) 的时间复杂度降到 O(k3logn) ( k 为矩阵的大小,通常小于10)

先给出矩阵乘法的模板代码:

struct MAT {
	int c[15][15],n,m;
	MAT() {
		memset(c,0,sizeof c);
	}
	MAT(int x,int y,int flag=0) {
		n=x,m=y;
		memset(c,0,sizeof c);
		if(flag)for(int i=1; i<=n; i++)c[i][i]=1;
	}
	MAT operator *(const MAT &a)const {
		MAT res(n,a.m);
		for(int i=1; i<=n; i++)
			for(int j=1; j<=a.m; j++)
				res.c[i][j]=c[i][1]*a.c[1][j]+c[i][2]*a.c[2][j]+c[i][3]*a.c[3][j],res.c[i][j]%=mod;
		return res;
	}
} A[9],B(1,3);
MAT qpow(MAT A,int q) {
	MAT res(A.n,A.m,1);
	while(q) {
		if(q&1)res=res*A;
		q>>=1;
		A=A*A;
	}
	return res;
}

这里乘的时候可以直接循环展开(手撕循环)常数大减。

以斐波那契数列讲一下矩阵乘法的实现。

fi=fi1+fi2

转移方程可以转化为 [fifi1][1110]=[fi+1fi]

这里的乘法就可以用快速幂来解决。实现 O(logn) 的时间复杂度。

普通的矩阵加速还是太简单了。是否有更难的矩阵的应用呢。

有的,有的。

这里有线段树维护矩阵的题 [大魔法师](Loading - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

但是其实就是码量大一点而已,其他就很简单,把每一个魔法对应的矩阵都算出来即可。

而矩阵在图上的应用就是类 Floyd 的算法,比如限长负环,限长最短路等,都是可以用矩阵乘法来加速的,本质来说就是倍增法。

分段 dp :有些题可能dp的每一部分的转移方程都是不同的,这样的话就是你把每一个矩阵都搞出来,离散化一下,对每一个区间求一遍即可。如[Runner's Problem](Runner's Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)) (这都紫题了)

最重要的矩阵部分就是大名鼎鼎的动态dp (DDP)(电灯泡)

何为动态 dp, 就是本身就是一个 dp ,但是带修改的dp,或者说是查询某一个区间,这时候用线段树维护矩阵就是一个不错的选择。

就像树上问题一样,第一步是转化成链上的问题。当然,动态dp 是先转化成普通的线性dp

比如,最大连续和这个经典的dpdp[i][0]=max(dp[i1][0],dp[i1][1]),dp[i][1]=dp[i1][0]+a[i]

这个明显可以直接转化成矩阵的形式(当然是广义的矩阵乘法),[fi,0fi,1][0a[i]0inf]=[fi+1,0fi+1,1]

直接维护这些矩阵的就可以了,答案就是初始矩阵乘区间乘积即可。

当然难的 ddp 在树上的 ddp 但是蒟蒻还是太弱了,目前还是不会。

posted @ 2025-02-09 12:47  hnczy  阅读(15)  评论(0编辑  收藏  举报