洛谷P11288 [COTS 2017] 模板 Z1 自学式题解
集训第一次 CSP-S 模拟赛 T4,我认为 too hard,写一篇题解以巩固我自己的理解。可能也算低手向题解???
模拟赛题是 \(1 \le n, h \le 10^9\) 的,所以本篇题解的算法复杂度为 \(O(m\log m)\)。
对比原题,模拟赛给了 \(h=2\) 的部分分,以启发我们入手,因此沿用下模拟赛给的子任务。
下面值域全部写成闭区间 \([1, h]\)。
但实际上第一步就想不到。
Subtask 3 \(n, m \le 500, h=2\)
显然限制是 \(1\) 的区间毫无用处,还难看,直接删掉,剩下的元素个数记为 \(n'\)。
没有限制的区间方案数是独立的,删掉,最后乘上去。
把剩下的拼接起来……
我们并不关心前面做了什么,唯一要知道的就是这些限制区间里有没有出现 \(2\) 而已,那么不妨在状态中加入上一个 \(2\) 的位置。即设 \(f_{i,j}\) 为第 \(i\) 位前最后一个 \(2\) 的位置是 \(j\) 的方案数。
当 \(i\) 不是右端点的时候,先不用管区间限制,后面有可能能把限制填上。
- \(a_i\) 填 \(1\)(\(j < i\)):\(f_{i,j} = f_{i-1,j}\)。
- \(a_i\) 填 \(2\)(\(j = i\)):\(f_{i,j} = \sum_{k=0}^{i-1} f_{i-1,k}\)。
对于区间右端点,我们就需要考虑限制了。限制都是 \(h=2\),那他们其实没有什么区别。以 \(i\) 为右端点的区间里,左端点最大的记该左端点为 \(p_i\),则可以分类讨论写出 \(f_{i,j}\) 的转移:
- 若 \(j < p_i\),就是说最紧的这个限制区间没有 \(2\),这不合法,\(f_{i,j} = 0\)。
- 若 \(p_i \le j < i\),则限制是都满足了,而且 \(a_i = 1\),对方案数没有什么贡献,\(f_{i,j} = f_{i-1,j}\)。
- 若 \(j = i\),则 \(a_i = 2\),从所有状态进行转移:\(f_{i,j} = \sum_{k=0}^{i-1} f_{i-1,k}\)。
边界条件 \(f_{0,0} = 1\)。
则答案为 \(2^{n'-n''}\sum_{i=0}^{n''} f_{n'',i}\),其中 \(n''\) 是删除无限制元素之后的元素个数。
时间复杂度 \(\mathcal{O}(n^2)\)。
Subtask 4 \(n \le 10^9, m \le 500, h=2\)
这显然让我们思考一个复杂度关于 \(m\) 的算法。
观察结构,把每一次 \(h=2\) 的限制看做对去除 \(1\) 限制区间和无限制元素后的序列进行切割,切割成一堆小段。
而每个段内怎么填是好处理的,因此我们对离散化后的段进行 DP。类似上文考虑,设 \(f_{i,j}\) 为第 \(i\) 个段,上一个 \(2\) 填在第 \(j\) 个段的方案数。转移类似,注意受到限制的时候必须填 \(2\)。设段长为 \(l\),总方案数减去不填 \(2\) 的方案数,容斥一下容易得到为 \(2^l - 1\),受限制的段转移如下:
正解 \(n, h \le 10^9, m \le 10^6\)
到此朴素做法已经显然了:上面删去 \(x_i=1\) 的做法启发我们,遵循 \(x_i\) 小的限制覆盖掉大的限制,然后按 \(x_i\) 从小到大处理限制。转移方程就是把 \(2\) 换成每一层的 \(x\) 而已。别忘了乘上 \(h^{n'-n''}\)。
如果有限制(右端点):
如果无限制(不是右端点):
但这是 \(\mathcal{O}(m^2)\) 的,过不了。注意到我们只需要记录上一个 \(i\),至于 \(j\) 那一维显然可以线段树维护,时间复杂度 \(\mathcal{O}(m\log m)\)。
我不认为这个必须离散化、只跟 \(m\) 有关的复杂度对原题来讲算一种加强。
处理区间写了扫描线 + ODT 嘻嘻嘻嘻哈哈哈哈。
写的什么破玩意一坨史。下标和各种映射很乱,如果你一定要看代码,可以把它喂给 AI 先让它帮忙重写一遍……

浙公网安备 33010602011771号