LOJ#6074 「2017 山东一轮集训 Day6」

LOJ#6074 「2017 山东一轮集训 Day6」

转自 https://www.dazhuanlan.com/2019/12/10/5deec6dec86e4/

原文的 markdown 都挂了,这里修修

设字符集大小为 m,这里 \(m=9\),假设字符从 \(0\) 开始标号。

显然可以 DP,设 \(dp_{i,j}\) 表示前 \(i\) 个字符中,以字符 \(j\) 结尾的本质不同的子序列个数。特殊地,\(j=m\) 表示子序列为空。有方程:

\[dp_{i,j}=\begin{cases}dp_{i-1,j} \text{ if } j \ne S_i \\\sum_{k=0}^{m} dp_{i-1,k} \text{ if }j=S_i \end{cases} \]

初始值是 \(dp_{0,m}=1\)。 发现 dp 数组可以写成行向量,记 \(F_i=\begin{pmatrix}dp_{i,0}\cdots dp_{i,1} \cdots dp_{i,2} \cdots dp_{i,m}\end{pmatrix}\)

而转移可以表示为一个行向量乘上转移矩阵 \(M_i\) 的形式:

\[\begin{aligned}M_i = \begin{pmatrix}1 & & 1 & & \\ & 1 & 1 & & \\ & & 1 & & \\ & & \vdots & \ddots & \\ & & 1 & & 1 \end{pmatrix} \\\\ F_i &= F_{i-1}M_i \end{aligned} \]

\(M_i\) 是一个主对角线为 (1),\(S_i\) 这一列为 (1),其余为 (0) 的矩阵。

初始的行向量为 \(A=\begin{pmatrix}0 & 0 & 0 & \cdots & 0 & 1\end{pmatrix}\)

最后由于是求 $$ \left(\sum_{i=0}^m dp_{n,i}\right)-1 $$ 所以最后需要乘上列向量

\[B=\begin{pmatrix}1 \\ 1 \\ 1 \\ \vdots \\ 1 \end{pmatrix} \]

于是对于每个询问,答案可以表示成

\[\begin{aligned}ans&=AM_lM_{l+1}M_{l+2}\cdots M_{r}B\\&=AM_{l-1}^{-1}M_{l-2}^{-1}\cdots M_1^{-1}M_1M_2\cdots M_{r}B\end{aligned} \]

直接维护 \(M_i\)\(M_i^{-1}\) 的前缀积(注意顺序),时间复杂度 \(O(nm^3+qm^3)\)

在维护完 \(M_i\)\(M_i^{-1}\) 后,分别右乘一个 B 和左乘一个 A,这样询问部分的复杂度可以降到 \(O(qm)\)

预处理部分,我们来观察一些特殊性质。对于 \(M_i\) 的前缀积,我们发现每次要算

\[\begin{aligned}CM_i&=\begin{pmatrix}C_{0,0} & C_{0,1} & C_{0,2} & \cdots & C_{0,m} \\ C_{1,0} & C_{1,1} & C_{1,2} & \cdots & C_{1,m} \\ C_{2,0} & C_{2,1} & C_{2,2} & \cdots & C_{2,m} \\ & & & \ddots & \\ C_{m,0} & C_{m,1} & C_{m,2} & \cdots & C_{m,m} \end{pmatrix}\begin{pmatrix}1 & & 1 & & \\ & 1 & 1 & & \\ & & 1 & & \\ & & \vdots & \ddots & \\ & & 1 & & 1 \end{pmatrix} \\ &= \begin{pmatrix}C_{0,0} & C_{0,1} & \sum_{j=0}^m C_{0,j} & \cdots & C_{0,m} \\ C_{1,0} & C_{1,1} & \sum_{j=0}^m C_{1,j} & \cdots & C_{1,m} \\ C_{2,0} & C_{2,1} & \sum_{j=0}^m C_{2,j} & \cdots & C_{2,m} \\ & & & \ddots & \\ C_{m,0} & C_{m,1} & \sum_{j=0}^m C_{m,j} & \cdots & C_{m,m} \end{pmatrix}\end{aligned} \]

相当于把 \(C\) 的第 \(S_i\) 列改成对应行的 \(C_{k,j}\) 之和。且最后乘上 \(B\) 相当于求每行的和。那么只要维护 \(C\) 的每一行之和即可。于是维护 \(M_i\) 的前缀积乘上 \(B\) 的复杂度变成了 \(O(nm)\)

对于 \(M_i^{-1}\) 的前缀积,我们先根据矩阵求逆的过程手动求出 \(M_i^{-1}\),发现

\[M_i^{-1}=\begin{pmatrix}1 & & -1 & & \\ & 1 & -1 & & \\ & & 1 & & \\ & & \vdots & \ddots & \\ & & -1 & & 1 \end{pmatrix} \]

\(M_i^{-1}\) 是主对角线为 \(1\),第 \(S_i\) 列除了第 \(S_i\) 行外是 \(-1\) 的矩阵。

维护 \(M_i^{-1}\) 的前缀积时,我们要算

\[\begin{aligned}M_i^{-1}C&=\begin{pmatrix}1 & & -1 & & \\ & 1 & -1 & & \\ & & 1 & & \\ & & \vdots & \ddots & \\ & & -1 & & 1 \end{pmatrix}\begin{pmatrix}C_{0,0} & C_{0,1} & C_{0,2} & \cdots & C_{0,m} \\ C_{1,0} & C_{1,1} & C_{1,2} & \cdots & C_{1,m} \\ C_{2,0} & C_{2,1} & C_{2,2} & \cdots & C_{2,m} \\ & & & \ddots & \\ C_{m,0} & C_{m,1} & C_{m,2} & \cdots & C_{m,m} \end{pmatrix} \\ &= \begin{pmatrix}C_{0,0}-C_{2,0} & C_{0,1}-C_{2,1} & C_{0,2}-C_{2,2} & \cdots & C_{0,m}-C_{2,m} \\ C_{1,0}-C_{2,0} & C_{1,1}-C_{2,1} & C_{1,2}-C_{2,2} & \cdots & C_{1,m}-C_{2,m} \\ C_{2,0} & C_{2,1} & C_{2,2} & \cdots & C_{2,m} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ C_{m,0}-C_{2,0} & C_{m,1}-C_{2,1} & C_{m,2}-C_{2,2} & \cdots & C_{m,m}-C_{2,m} \end{pmatrix}\end{aligned} \]

可以发现,每一列除了 \(S_i\) 这一行以外都减去的是同一个数,于是我们维护每一列减去的数,例如对于某一列

\[\begin{pmatrix}x_0-v \\ x_1-v \\ x_2-v \\ \vdots \\ x_m-v \end{pmatrix} \]

要变成

\[\begin{pmatrix}x_0-v-(x_2-v) \\ x_1-v-(x_2-v) \\ x_2-v \\ \vdots \\ x_m-v-(x_2-v) \end{pmatrix}=\begin{pmatrix}x_0-x_2 \\ x_1-x_2 \\ (2x_2-v)-x_2 \\ \vdots \\ x_m-x_2 \end{pmatrix} \]

于是只需要修改第 \(S_i\) 那一行的值,并且更新每一列减去的值即可。

最后左乘 \(A\) 相当于求最后一行的值。由于最后一行不会修改,始终是

\(\begin{pmatrix}0 & 0 & 0 & \cdots & 0 & 1 \end{pmatrix}\)

所以直接减去对应列需要减的数即可。这一部分的时间复杂度也变成了 \(O(nm)\)

总时间复杂度 \(O(nm+qm)\)

posted @ 2020-12-11 21:39  Hs-black  阅读(117)  评论(2编辑  收藏  举报