矩阵相关

25.08.12

矩阵加速递推

向量的定义及基本运算

不想写。这边建议 bdfs.

矩阵乘法

矩阵可以看作列向量的行向量。因为行向量点乘列向量是一个数,行向量乘上一个矩阵就是一个行向量,结果的每个元素都是原行向量乘上对应列的列向量得到的结果。

矩阵相乘只有在第一个矩阵的列数和第二个矩阵的行数相同时才有意义。设
\(A\)\(P\times M\) 的矩阵,\(B\)\(M\times Q\) 的矩阵,设矩阵 \(C\) 为矩阵 \(A\)\(B\) 的乘积,则 \(C\) 的第 \(i\) 行第 \(j\) 列的元素 \(C_{i,j}\) 满足

\[C_{i,j}=\sum A_{i,k}B_{k,j} \]

或者你可以继续用上面的思想,把 \(A\) 看作行向量的列向量,把 \(B\) 看成列向量的行向量,这也是符合向量的运算原理的。

线性变换

对于一个把向量 \(A\) 变成向量 \(B\) 的变换,如果 Ta 满足下列性质,则称其是一个线性变换。

  1. 可加性。\(f(A+B)=f(A)+f(B).\)
  2. 齐次性。\(f(kA)=kf(A).\)

我们一般可以认为线性变换对于 \(A\) 中的每个元素进行下面这个样子的运算:

\[f(A_i)=\sum k_{i,j}A_j \]

其中 \(k_{i,j}\) 为仅和 \(i,j\) 有关的常系数。

正因如此,任意线性变换的过程都一定可以用“乘上一个系数方阵”来表示。举个例子:

\[\left[ A_1\quad A_2\right]\times\left[\begin{aligned}k_{1,1}\quad k_{1,2}\\k_{2,1}\quad k_{2,2}\end{aligned}\right]=\left[k_{1,1}\times A_1+k_{1,2}\times A_2\quad k_{2,1}\times A_1+k_{2,2}\times A_2\right] \]

乘上一个方阵,就可以看作进行了一次线性变换。线性变换是满足结合律的,所以当一个 dp 过程对于每一项都是同一个线性变换时,我们就可以尝试使用矩阵快速幂加速递推过程。

至此你学会了矩阵加速递推。

广义线性变换

我自己取的名字,轻喷。

一个 dp 过程有时候并不恰好为线性变换,比如下面这个转移方程:

\[dp_i=7\times dp_{i-1}+9\times dp_{i-2}+5i^2+3^i+19 \]

在线性变换的基础上追加了一个关于 \(i\) 的函数。我们称其为广义线性变换。

广义线性变换也是可以用矩阵表示的,只不过用于转移的行向量需要增加一些元素。

说人话就是我们希望 \(\left[dp_i\quad dp_{i-1}\quad i^2\quad 3^i\quad i\quad 1\right]\) 乘上某一个方阵之后变成 \(\left[dp_{i+1}\quad dp_i\quad (i+1)^2\quad 3^{i+1}\quad i+1\quad 1\right]\).

这里增加 \(i\)\(1\) 这一项是为了能够“线性地”递推出 \((i+1)^2\) 以供后续递推。而对于常数项,我们总数能够通过在转移向量中追加一个 \(1\) 来完成转移。\(\LaTeX\) 敲起来非常累,所以最后的答案我就不写了,拿草稿纸很快就列出来了。

矩阵,不止加速递推

例题:[THUSC 2017] 大魔法师.

简要题意:维护一个 \(3\) 维向量的序列,需要支持区间广义线性变换,区间向量和查询。答案对 \(998244353\) 取模,\(1\le n,m\le 2.5\times 10^5\).

正因为矩阵乘法有着结合律这样优秀的性质,我们可以直接上线段树。

具体地,我们通过维护一些辅助信息将广义线性变换表示为普通线性变换之后,可以写一颗线段树,线段树的 lazytag 是一个矩阵表示其表示的区间都要乘上的矩阵。初始时,所有 lazytag 都是单位矩阵 \(I\)。这题就做完了。

动态 dp(DDP)

矩阵果然很厉害,但是也没有几道 dp 题的转移方程就摆个(广义)线性变换啊,有没有更厉害的应用呢?

有的兄弟,有的。

广义矩阵乘法

我们将矩阵乘法中的 "\(\times\)" 换成 "\(+\)", 而 "\(+\)" 换成 "\(\min/\max\)", 重新定义矩阵乘法。为避免混淆,这里用 \(\odot\) 表示广义矩阵乘法。

对于 \(C=A\odot B\), 有:

\[C_{i,j}=\min/\max A_{i,k}+B_{k,j} \]

广义矩阵乘法有什么用呢?我们随便拿个向量和矩阵进行一次广义矩阵乘法,得到:

\[\left[ A_1\quad A_2\right]\odot\left[\begin{aligned}w_{1,1}\quad w_{1,2}\\w_{2,1}\quad w_{2,2}\end{aligned}\right]=\left[\min/\max(A_1+w_{1,1},A_2+w_{1,2})\quad \min/\max(A_1+w_{2,1},A_2+w_{2,2})\right] \]

\(A\) 看作 dp 数组的一部分,把 \(w\) 构成的矩阵看作代价函数,是不是就长得有点像正常的线性 dp 柿子了?

而且,可以证明广义矩阵乘法仍然具有结合律(我不会证)。

所以,我们上线段树。

dp 过程的区间化

例题:P4513 小白逛公园.

简要题意:单点修改,区间询问最大子段和。

最大字段和的转移方程非常简单, \(f_i=\max(f_{i-1},0)+a_i\).

那么显然地有 \(\Theta(mn)\) 的做法,每次询问 dp 一遍。动态 dp, 在这里可以简单理解为加速这一过程。

把这个转移方程对每个 \(i\) 矩阵化记为 \(M_i\). 具体地,若将答案向量定义为 \(A_i=\left[f_i\quad res\quad 0\right]\), 则有:

\[\begin{aligned}f_i&=\max(f_{i-1}+a_i,a_i)\\ res&=\max(res,\max(f_{i-1}+a_i,a_i))\\ 0 &= 0\end{aligned}\\ \]

也就是说:\(A_{i-1}\odot M_i=A_i\) 这样一个转移过程可以表示为:

\[M_i=\left[\begin{aligned} a_i &\quad& a_i&\quad& -\infty\\ -\infty &\quad& 0&\quad& -\infty\\ a_i &\quad& a_i&\quad& 0\\ \end{aligned}\right]\]

我们要求的 \([l,r]\) 的最大子段和其实就是 \(B=A_0\odot M_l\odot M_{l+1}\odot\dots\odot M_r\)\(res\) 那一维的信息。

用线段树维护区间转移矩阵的广义乘积即可。

完整代码在 这里

升级版例题:Can you answer these queries VII.

简要题意鸽了。

反正树剖之后发现我们要在上一道题的基础上多维护一个区间推平的操作。这也是容易做的,因为我们显然可以使用矩阵快速幂一次性计算推平操作对一个区间的影响。整道题就快速地做完了。

DDP

动态 dp, 不仅仅是加速 dp 过程,更重要的是支持修改。

例题:P4719 【模板】动态 DP.

posted @ 2025-11-26 19:39  xwxabc  阅读(3)  评论(0)    收藏  举报