arc159_F DP

发布时间 2023-04-14 01:52:57作者: wiki0922

题意(简化版)

给出一个长度为 \(2n\) 的序列 \(a_i\),求将序列分割为若干个长度为偶数的区间,满足每个区间内都不含绝对众数(出现次数严格大于长度的一半的数)的方案数。

\(n\le 500000,\,a_i\le2n\)

解法

解法和官方题解大致相同,虽然官方题解我也没看太明白(

显然一定在偶数出断开,所以可以先将序列两两分组,即 \(p_i=(a_{2i-1}, a_{2i})\) ,变成由 \(n\) 个二元组组成的序列。

为方便叙述,这里将二元组 \(p_i\) 的第一个元素记作 \(x_i\),第二个记作 \(y_i\)

考虑 dp,用 \(f_i\) 表示前 \(i\) 个二元组的合法分割方案数,那么 \(f_i = \sum\limits_{(j, i]\,is\,available} f_j\),发现统计合法的转移是一个比较困难的工作,考虑正难则反,使用总和减去不合法的转移,那么

\[f_i = \sum_{j=1}^{i-1}f_j-\sum_{(j,i]\;is\;not\; available}f_j \]

那么如何统计不合法的转移呢,首先发现每个不合法的转移中只会有一个绝对众数,那么可以考虑枚举绝对众数,对于绝对众数 \(v\) 分别统计。

具体统计时,需要使用一个我不知道的绝对众数经典 trick,对于每个二元组 \(p_i\) 赋一个权值 \(w_i\):若 \(x_i\)\(y_i\) 都等于 \(v\)\(w_i = 1\);若 \(x_i\)\(y_i\) 其中有一个为 \(v\)\(w_i=0\);若 \(x_i\)\(y_i\) 都不为 \(v\)\(w_i=-1\)

那么 \(v\) 为某一区间的绝对众数当且仅当该段区间的权值和为正,所以可以对权值做前缀和。

于是当前 dp 到 \(i\),枚举的绝对众数为 \(v\) 时,我们可以 对于每一权值前缀和 \(val\) 统计其对应的所有 \(j\)\(f_j\) 之和 \(memo_{val}\),即 \(memo_{val} = \sum\limits_{j=1}^n\left[\sum\limits_{k=1}^j w_k= val\right] f_j\),由于 \(i\) 的权值前缀和 \(s\) 的变化是连续的,\(memo\) 的前缀和很容易维护。减去不合法方案只需让 \(f_i\) 减去 \(memo\) 的前 \(s-1\) 项的前缀和。

于是我们便得到了一个 \(\mathcal{O(n^2)}\) 的算法。

如何优化呢,发现我们 dp 时做了许多无用的操作,其实可以先对于每个绝对众数 \(v\) 求出所有有可能以 \(v\) 为绝对众数的区间的并集,这个并集大小是与 \(v\) 的出现次数同阶的,于是对于所有 \(v\),这个并集大小的和是 \(\mathcal O(n)\) 的!

对于每个 \(v\),它的并集一定是由多个彼此不相连的区间构成的,对于每个区间分别统计其 \(memo\) 并转移即可。

时间复杂度 \(\mathcal{O(n)}\)