矩阵相关
立个 \(flag\),已经连续两年考这玩意儿了,今年一定不会了
矩阵运算
加减:要求行列数一致,对应位相加减
乘:对于 \(A * B\),答案 \(ans[i][j]=\sum a[i][k] * b[k][j]\),要求第一个矩阵列数等于第二个矩阵行数。注意矩阵乘法具有结合律但不具有交换律
矩阵转置:将矩阵的行列互换得到的新矩阵称为转置矩阵,转置矩阵的行列式不变。直观来看,将M的所有元素绕着一条从第1行第1列元素出发的右下方45度的射线作镜面反转,即得到M的转置,记为 \(M^T\)
性质:
\((M^T)^T=M\)
\((M+N)^T=M^T+N^T\)
\((kM)^T=kM^T\)
\((MN)^T=M^TN^T\)
实现时注意如果重载运算符数组默认值并不是零,需要 \(memset\) 暴力更改
\(update\):据 \(dky\) 大大说循环写 \(i,k,j\) 会快一点
- 矩阵求逆
首先声明并不是所有矩阵都有逆(貌似是得满秩?)
具体做法是对于原矩阵 \(A\),往右边拼一个单位矩阵 \(B\),然后对着 \(AB\) 开始消元
如果最终 \(A\) 被消成了对角矩阵,那么此时的 \(B\) 就是逆矩阵了
貌似需要求逆矩阵的场景较少?
由于矩阵贡献不可逆,常常与双栈模拟队列的方式结合,可以做到不用删除,具体见 队列与栈
矩阵优化递推
最常见的斐波那契有递推式 \(f_i=f _ {i-1}+f _ {i-2}\)
如果只需要知道第 \(n\) 项的值(\(n\) 很大),可以这样做:
定义初始矩阵:
要乘一个转移矩阵 \(B\) 结果为答案矩阵
那么 \(B\) 可以构造为:
通过定义可以证明这样构造是对的
根据矩阵的结合律,最终要乘 \(n\) 次转移矩阵,不妨先求转移矩阵的 \(n\) 次方然后再乘初始矩阵
而 \(n\) 次方可以快速幂优化
矩阵优化的要求:
常量与变量之间是相乘关系,而变量和变量之间只能是相加关系
其余情况可以通过原根、指数等方式转化为加法关系
然后有进阶版:P3216 [HNOI2011]数学作业
发现这回递推式变成了 \(f_i=f_{i-1}*lg(i)+i\)
发现 \(lg(i)\) 是变量不好处理,但是值总共只会变 \(log\) 次,所以分段处理即可
每组中初始矩阵为:
很容易写出转移矩阵:
分组进行快速幂转移即可
如果递推扩展到二维,比如这道题:
首先可以类似地推导出行和列分别的转移矩阵 \(A_1\) 和 \(A_2\)
那么可以假定先转移行,然后更新一边列,能推出下面的式子:
然后再快速幂优化即可
对于每一个操作都可以写出一个转移矩阵,当区间询问不能暴力相乘
考虑到矩阵乘法的结合律,用线段树维护区间矩乘即可
由于次方的相乘等价于指数的相加
那么处理出每个 \(f_{1\sim k}\) 的次数即可
由于转移方程均相同,可以直接预处理
考虑将分数用矩阵 $$\begin{bmatrix} x & y \end{bmatrix}$$ 维护
考虑添加一个 \(a\) 造成的贡献,是乘矩阵
类似地,发现两种操作对分数的影响也是可以用矩阵表示出来的(太难打了不写了)
至此变成了矩阵乘法问题,平衡树来维护,需要维护正反分别对换的四种情形
矩阵优化图上问题
\(Cyber\_Tree\)曾经说过这类矩阵以后就叫 \(Cyber\_Tree\) 矩阵
对于图上的 \(dp\),有限制为与一个点有连边的点才能转移
而如果进行多次这样的操作,可以用矩阵把状态的转移记录下来,用快速幂优化
比如这道题,除了终点一个点可以向相邻点连边,那么表达在矩阵上即为 \((i,i+1)\) 以及 \((i,i-1)\) 的位置为 \(1\)
快速幂后即可知道方案数是多少了
基本一模一样,这需要建立爆炸虚拟点,所有点向其连边,所有点向自己连边即可
这道题多了一个限制是不能走刚走过的边
那么矩阵里如果保存点是刻画不出来这个限制的
考虑到边的范围也不大,矩阵直接维护边的相互到达即可
对于边权不大的转移,将一条边拆成多个点即可
非常新颖的一道题
考虑到鱼的周期都不大,直接枚举周期即可
发现 \(lcm\) 为 \(12\),那么每 \(12\) 个一组进行快速幂,多余部分单独处理
预处理出周期内每个时刻的转移矩阵
广义矩阵运算
观察矩乘的式子:\(ans[i][j]=\sum a[i][k]*b[k][j]\)
假如想求最短路,方程式为 \(dis[i][j]=min(dis[i][k]+dis[k][j])\)
发现这俩长得挺像
那把矩乘重定义成先加后取 \(min\) 就好了(当然也可以定义成别的)
比如这道题就是求最短路
这道题把矩乘重定义为:\(ans[i][j]=\oplus a[i][k] * b[k][j]\)
然而发现有多组询问复杂度不太对了
那么先预处理出 \(2\) 的整数幂的矩阵乘积就可以 \(n^2\) 快速幂转移了
CF576D Flights for Regular Customers
首先按要求边数从小到大排序
然后一条一条往里加,判断是否能到达终点
用矩乘处理出加入这些边后在限定时间内能到达的点,然后从这些点出发跑多源最短路(由于边权为 \(1\) 实际上是 \(bfs\))
这道题之要求能不能到,矩阵重定义为 \(ans[i][j]|=a[i][k]\&b[k][j]\)
这个可以丢给 \(bitset\) 进行优化
循环节意义下的矩乘
比如这个题的处理方式,每次 \(dp\) 相当于往后推了一个循环节
设 \(f[n][i][j]\) 表示以第一个循环节 \(i\) 开头,以后面第 \(n\) 个循环节的 \(j\) 结尾的 LIS 长度,转移:
然后用广义矩阵乘法的方法优化一下
设 \(f[n][m]\) 表示答案,则有转移 \(f[n][m]=(n-2(m-1))f[n-1][m-1]+2mf[n-1][m]\)
由于 \(mod\) 非常小,那么矩阵的循环节是固定的
求出 \(mod\) 个不同的转移矩阵再前缀和即可
一个更普遍而巧妙的做法是考虑从大到小加入,设 \(f[i][j]][k]\) 表示目前加入多少个数,形成了 \(j\) 个山峰,形成了 \(k\) 个独立联通块的方案数
可以发现这样的转移是与 \(i\) 没有关系的,可以求出后两位求出矩阵
循环矩阵
循环矩阵即行向量的每个元素都是前一个行向量各元素依次右移一个位置得到的结果
对于从左边几个和右边几个转移的 \(dp\),转移矩阵可能形成循环矩阵
循环矩阵有性质是加和与乘积还是循环矩阵
那么一种快速的乘法这样计算(设 \(g_i\) 表示第一行的第 \(i\) 个元素):
于是时间复杂度降为 \(n^2\)
另一种形成循环矩阵的方式比较巧妙,利用原根将乘法变为加法后转化成这种形式
比如这道题就是一个典型的例子,\(dp\) 的转移之间是由乘法架构的