加载中...

杭电春季赛5 1004(矩阵乘法优化dp)

1004

考虑缩小问题规模:

首先,可以将 1~n 序列内的所有数都模 \(m\),这样值域就缩减为了 \([0, m - 1]\)

其次,对于模 \(m\) 的某个剩余类内的所有数,选其中的 \(i\)\(m + i\)\(2m + i\)... \(km + i\) 个数并无差别。这样 \([0,m - 1]\) 内每个数的个数也可以缩减到 \(<= m\) 的范围内来考虑。

至此,所有相关的数据范围都被缩减到了 \(m\) 以内。可以考虑 \(dp\):

\(dp[i][j][k]\):考虑数字0~i,其中选 \(j\) 个数字 \(i\),选取的子集内所有数之和模 \(m\)\(k\),方案数。

显然 \(ans = \sum_{j=0}^{m-1}dp[m - 1][j][0]\)

\(trans\)

\[dp[i][j][(k + i * j)\space mod \space m] = \sum_{j=0}^{m-1} dp[i - 1][j][k] \times d[i][j] \]

\[d[i][j] = C_{num[i]}^{j} + C_{num[i]}^{j + m} + C_{num[i]}^{j + 2m} + ... + C_{num[i]}^{j + km} \]

第二维可以利用前缀和优化 \(dp\) 加速。

转移复杂度看似也是 \(O(m^{3})\) 的,但实际上 \(d[i][j]\) 的计算也非常耗时。

(本篇重点)考虑如何计算 \(d[i][j]\)

观察 \(d[i][j]\) 的表达式,其中 \(num[i]\) 的范围特别大,不可能计算其中的每一项。可以利用 \(d[i][j]\) 的定义式来巧妙转换下思路:

\(d[i][j]\) 的另一种表述:有 \(num[i]\) 个数字,这些数字两两不同(在模 \(m\) 之前,它们是互不相同的),要求选择的数字数量 模\(m\) 后为 \(j\),方案数。

定义 \(f[i][j]\):考虑前 \(i\) 个数,选取它们的某个非空子集,数量 模\(m\) 后为 \(j\),方案数。

数组 \(f\) 的转移式可表示为:

\[f[i][j] = f[i - 1][j] + f[i - 1][j - 1] \]

特殊地,当 \(j = 0\) 时,有:

\[f[i][j] = f[i - 1][0] + f[i - 1][m - 1] \]

这里的 \(i\) 会达到 \(O(n)\) 级别,特别大,不可能直接递推。

考虑用矩阵来加速递推过程:定义矩阵 \(A\)(大小以 \(7 \times 7\) 为例,实际大小为 \(m \times m\)):

\[ \left\{ \begin{matrix} 1 & 1 & 0 & 0 & 0 & 0 & 0\\ 0 & 1 & 1 & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 1 & 0 & 0 & 0\\ 0 & 0 & 0 & 1 & 1 & 0 & 0\\ 0 & 0 & 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 0 & 0 & 0 & 1 & 1\\ 1 & 0 & 0 & 0 & 0 & 0 & 1\\ \end{matrix} \right\} \]

并设大小 \(1 \times m\) 的矩阵 \(B\) 为:

\[ \left\{ \begin{matrix} 1 & 0 & 0 & 0 & 0 & 0 & 0\\ \end{matrix} \right\} \]

\(d[i]\) 实际上是一个 \(1 \times m\) 的矩阵。矩阵 \(A\) 实际上就是每一步转移时的因子(每一轮都固定,因此最终可以表示为 \(A\) 的次幂,可以用矩阵快速幂计算)。而矩阵 \(B\) 就是 \(f[0]\)中初始的每一项(只有 \(1\) 种方案:不选数字。模 \(m\) 结果默认为 \(0\))。

因此,\(d[i]\)\(A\)\(B\) 之间的转移式可写作:

\[d[i] = B \times A^{num[i]} \]

其中 \(A^{num[i]}\) 这一项用矩阵快速幂来直接计算。

对于 \(i \in [0, m - 1]\) 中的每一项,都按上述方式计算,总复杂度是 \(O(m^{4}logn)\) 的(不是最优的复杂度,提交也会 \(TLE\),不过整个过程都是本蒟蒻自己摸索出来的,只是为了做一次记录。正解暂时还不想补qwq...)

TLE code

posted @ 2025-04-05 15:43  jxs123  阅读(30)  评论(0)    收藏  举报