P8478 清明 的亚指数时间做法
“何必偷光 赐我以绚烂 却徒留不甘”
本题存在亚指数时间做法,把题解区里一堆做法拼起来就可以做出来,在此给出一种可以在 时间内理论解决本题的做法。
参考了 官方题解 与 ningago 的题解 在 时的多项式时间做法。
如果你已经完全掌握官方的 时间的做法,可以直接跳至 Part3 开始阅读,本文对前半部分的叙述比较 abstract,如有不理解可以参考其他题解。
Part1.
令第 层向 层流出的水量为 ,若 或 时 。
则要求等价于对所有合法的流量矩阵,即满足 (每一层留给自己和后 层水量的和确定) 的所有 数组,求 的和。 (这个过程形如“行和确定,分配给列” and then “对列和求乘积”)
面对这种 形式且值域极大、难以计算的式子,我们的想法自然会是用乘法分配律(组合意义)把里面 拆出来,变成对于所有合法的限制,求 的形式。
考察拆开括号 这样的括号,我们等于要在每个括号内选取恰好一项,并求其在所有满足限制情况下乘积的和。我们假设第 个括号选取了项 。 最终的乘积就是 。我们再按照每一个限制的顺序,考虑去满足第一个 上的这些限制,我们依次考虑:对于每个 限制的和 , 出现在了哪些 的括号里 。
这个时候可以发现对于一组确定选取的 ,我们并不关心它们各自的值,只关心每个 构成的可重集 。 因为限制之间是独立的,而我一旦知道了对于一个限制 有 个 被选入乘法里了,那么所有 的项对整个乘法的贡献就确定了,就是若干个独立的下面这个问题:
”所有长度为 ,和为 的自然数序列的某 项的积的和是多少?“(因为每个位置等价,不妨转成前 位,这里的 和 取个 min,即实际的窗口长度)
而这个问题是简单的,有很多种方式统计出,用组合意义把它看成 个无标号球进 个盒子,前 个盒子再选一个球的方案数。 转置顺序后等于先选 个特征点出来,交替设置为球和板子,可以直接插出来答案是 。
于是对于一组确定的 (由某种括号内选择方案生成出的每个限制被选取的次数),我们可以快速算出满足所有限制的方案的乘积的和,它们之间独立,我们将其相乘。
接下来我们就可以直接按 的顺序生成 ,枚举任意一个目前未确定 的 的集合的子集,然后将其设为已选择并产生一个仅和这个集合大小相关的系数。仅需记录 个状态,即可能被选择的之后 个括号是否被占据即可。
直接转移可能会带有一个枚举子集的 ,然而我们本质是在做子集卷积,甚至第二个幂级数的大小也只和集合大小相关,所以可以再开一维表示增加的量,做高位前缀和就行。
时间复杂度 。
该做法在 时,我们不再关心之后具体被占据的是哪些括号了。可以直接从后往前 dp 的过程中,直接用一个数来记录目前还有几个括号没有选出。容易做到 。
Part2.
注意到 较大的时候整个问题是很接近 的问题,只是在后 个位置的 不能被所有括号取到,而其它都可以任意选择。所以我们考虑继续仿照着 Part1 的办法,仍然从后往前 dp,只是再多记录一个 个 bit 表示最后几个位置是否被占用,而其它位置都等价,因此我们只需要记录数量即可,从后往前 dp 就行,直接做就可以做到 。
官方给了一个精妙的容斥方式,我们直接通过容斥来枚举并钦定后 项是否选择超出 距离的位置,用无限制减掉超出,如果钦定了位置 超出,就视作这个位置 上并没有一个可以选择的括号,而是直接在 的时候加入一个括号(这样它选择的就一定是一个之前距离超过 的数);如果不钦定,就直接在 位置上有一个括号,可以被前面所有数选择。
枚举这 个位置的 种超出情况,这个时候每种都是在每个位置上有若干括号,然后每个数可以出现在之后的所有括号里,出现 次会产生一个和 有关的乘法系数,和 part1. 的 做法完全相同,从后往前做即可。
时间复杂度 。
Part3.
参考了 ningago 的题解。
对于这种序列上两个位置差不超过 才能互相影响的题目,我们有一种尝试的策略: 将其分为长度为 的段,这样我们需要考虑的影响就只有两种:组内的任意匹配;对于相邻两组,前组的第 个和后组的第 个()。
我们现在将序列分成 组,每一组长度为 ,组内的位置之间距离都 ,一个数是可以出现在组内之后的任意括号的,而对于相邻两组,前组的第 个数可以出现在后组的前 个括号。我们把它每组一行化成这样一个图。

于是我们尝试将限制 可能选择的括号的两部分分别考虑:同行后面的,任意选,只关心每行后面还可以被选择括号的数量;以及它提前”占用“ 了多少下一行的括号:下一行的第 个位置之前的括号都可以被预支。
所以我们可以并行地从后往前推进 ,这样每行的位置就被 之前和 之后分成了两部分, 之前只会被预支给上一组的 之后的位置,我们只关心预支了多少个括号;而 之后的位置只能提供给这一组,我们只关心剩下了几个括号还能被选。
拿 ningago 的题解 中的 ,即两组的情况举例,我们可以这样 dp:
让 表达:目前已经从后往前考虑到每组的第 个限制所带来的系数,其中:
-
第一组 及之后还剩下了 个括号可以选
-
第二组 之前有 个括号被第一行的 及之后的括号用了
-
第二组 及之后还剩下了 个括号可以选
如果不考虑 本身这个括号,有这些组合结构上的系数:
第二组部分带来的系数是简单的,枚举这个数出现在了 个括号,这决定它本身的乘法系数,然后组合结构上直接在之后 个里面选 个,即 。
第一组部分带来的组合系数,枚举两个部分:这个数出现在了 个同组括号中, 个第二组的括号中,组合结构上的系数就是: 。第二部分表示重排目前的待补预支队列。
考虑 这个括号本身,需要在这两个系数上增加三种情况: 这个括号被选给自己, 这个括号被上一组预定了, 这个括号留给这一组的 之前的位置,会分别对 ,, 有 的影响。
所有括号都安排好自己选择的数,并且每行被预支括号都还清的情况下, 就是答案。
于是我们可以在 的时间内解决分两组的情况。
因为只可能相邻的两组之间才会有影响,所有这个做法完全可以扩展到有更多组的情况:我们并行地从后往前做每个组,需要记录在状态中的的东西依然形如
分别代表每一组 之后剩余的可以选择的括号里量,以及每一组被前一组预支的括号量,转移和在两行的情况下第一行的行为几乎完全相同。
总共有 组,我们总共要记录 个余量和 个预支量,对于每个 ,总状态量是 ,转移总是 的,复杂度可以做到 ,即 。
Part4.
在获得了 Part3 的 时间的做法后,接下来的拼接就是很经典的数据分治,指数拼分组并行,这个平衡思想和 多串最长公共子序列问题 和 最长非本原串问题 的 做法完全一样。(另一个同款思路题目)
在 较小时,直接采用 Part1 做法, 地记录被占用的位来统计,而在 较大时,采用 Part5 的做法,并行地通过 dp 统计 个长度为 的组来完成,时间复杂度 。
取平衡点 时,两边同时取 log,,取 ,得 ,此时两侧时间均不高于 。
这个优化在本题数据范围下难以展示更多分割的优越性了,本题数据范围下比较容易做到 优于目前最优解。那个真正分 组的做法有点变态,有人愿意吃的话可以来写一下,感觉在本题的数据范围下跑不快就是了。
“哪怕唯有余辉 能抵达
我依然会为你 献上最后的 盛大”