P8182 「EZEC-11」雪的魔法 题解

第一步:题意转化

做法一:线性规划对偶

详见 [ZJOI2020] 序列

这是本题唯一一个可能用到的所谓 “高深知识点”,“可能” 也就意味着本题存在的做法二。

做法二:贪心

为了方便叙述,我们先将题目表述为:

  • 我们每次让一个 \leq m 长的区间中所有的 a_i​ 消去 1,使得最终所有的 a_i 减为 0,求最少的消去次数。

容易发现消去的顺序与答案无关,换句话说,不管我们是从左往右消还是从中间开始消,我们只不过是把消的顺序调换了,因此我们从左往右,每次将消去区间的左端点放在左边第一个 a_i 不为 0 的位置,一定有一种方案是最优解。

如此以来,每次消去时左端点的选择已经固定,就是从左往右第一个 a_i 不为 0 的位置。那么,右端点应该如何选择?

  • 先考虑前 j (j\leq m) 个位置构成不减序列的情况。

这种情况下我们只需要直接将前 m 个位置全部消去 1 即可,因为由于这是不减序列,我们贪心地希望每次能够消去的东西尽量多,而在序列一直为不减序列的情况下,消去区间的长度始终为 m。相信这一部分读者很好理解。

  • 按照这种规律一直消到前 j' (j' < m) 个位置构成不减序列的情况。

我们发现,在 a_j_'​ 和 a_j_'+_1 之间存在一个 gap,这个 gap 必须要 (a_j_'-a_j_'+_1) 次右端点在 j' 的操作才能消去。那么,先消去这个 gap 显然是不劣的。

除此之外,我们需要充分利用这 (a_j_'-a_j_'+_1) 次操作,即使得这几次操作尽量多地消去。否则,如果我们先进行右端点超过 j' 的操作,将会使得 j' 前可消去的部分变少,就可能使得消 gap 操作消去的东西变少了,最终将会导致答案偏大。

因此结论就是:

我们仍然只需要让前 j' 个位置全部消去 1,直到 gap 消失。


从上述做法,我们知道仅有当 a_i>a_i+_1 时消去的区间长度小于 m。我们又知道,这个 gap 是必然要被消去的,问题只不过是消去的左端点在哪。

不妨直接将 (i-m+1) \sim i 消去至 gap 消失。即,令 k = a_i-a_i+1,我们使 a[(i-m+1)\sim i]-=k

这样操作之后,我们相当于把问题转换为:

  • 至少要多少次操作可以将每一个数字都减到 ≤0(不必正好等于 0)。

这是为什么呢?


首先,对于一个不减数列,在贪心地消去时,我们不用保证每个位置都被刚好减为 0,而是可以减为负数,这样做和原题的答案是相同的,这很显然。

那么,我们从左往右依次考虑每个 gap,第一个 gap 之前是个不减数列。

如果我们提前消去这个 gap,那么这对于右端点在 gap 之前的消去所产生的答案不变。

那么,由于消去的区间长度为 m,如果我们提前消去这个 gap,则当右端点移动到(或经过)原 gap 所在位置时,一定满足一个条件:

该位置前(m 个位置以内)一定是一个不减序列。

那么,我们就把问题转移到了第二个 gap,此时第二个 gap 之前已经是不减序列,依此类推。


另外,这种做法实际上还有一个问题:

既然我们提前消去,那么最终答案显然也要加上区间内提前消去的次数,并且我们的询问是在提前消去过后的数列上进行。

但是,对于我们询问的区间,在这个区间之后的 gap 提前消去的区间可能覆盖到询问区间内。对于这一部分 gap,如果我们也提前消去,那么将会导致答案不正确,因为这些 gap 根本不在区间内。如何解决这一问题?

事实上,有一个非常聪明和简洁的办法:当我们消到区间内最后 m 个位置时,此时的序列一定是不减的,因此最后 m 个位置的答案就是区间最后一个数的原值。而不在 gap 内的提前消去最多影响到区间的后 m 个位置。于是,非常凑巧地,我们只需要对提前消去后的数列,求出 [l, r-m] 的答案,再加上 a[r] 的原值以及 [l, r-1] 内所有 gap 的提前消去次数即可。


现在考虑如何求出提前消去之后的数列上某个区间的答案。

假定对于这个数列,我们消去的策略类似,依然是从左到右每次把左端点放在第一个 a[i] > 0 的位置上,并且不需要让 a[i] 刚好减为 0。那么,可以视为区间长度始终为 m。

那么,当左端点移动到 i 时,设 b[i] 为此时的 a[i]。那么,b[i] 就是左端点在 i 的消去次数。

使得 a[i] 减为 b[i] 的则是所有距离 m 以内的消去次数,即 b[(i-m+1)\sim (i-1)] 之和。于是我们写出式子

                        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​    b[i]=max(0,a[i]-\sum_{j=i-m+1}^{i-1}b[j])

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​   s[i]=\sum_{i=1}^{i}b[i]

可得

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​   s[i]-s[i-1]=max(0,a[i]-S[i-1]+S[i-m])

而所求答案即为 S[n]

我们发现,这个式子与以下问题等价:

  • 在长为 n 的数列上,每个长度为 m 的区间内最多有一个数字被选中,求最终选中的数字之和的最大值。

下面考虑如何解决这一等价问题。

主干解法 - 分类分治

我们对于原序列分段,每段长度为 m,共 [\frac{n}{m}] 段。然后,将分段后的序列排成一个矩阵,矩阵的每行为一个整块,即每行 m 个元素,共 [\frac{n}{m}] 行。更具体地,记矩阵的第 i 行第 j 列为 (i,j),(i,j) 对应原序列的第 ((i-1)\times m+j) 个位置。下面进行分类讨论。

  • Case 1:m<\sqrt{n}

对整个序列进行二分。具体地,在整个序列中间画一条竖线,也就是在整个矩阵的中间位置画一条横线,将整个矩阵从中间截断。对于跨越了这一分界线的询问区间,其必然存在一个跨越该分界线的长度为 (m−1) 的子区间,使得该子区间内没有数被选中。枚举这 m 个子区间,并且对于每个子区间的左端点,利用递推式预处理出其向左到任意点的答案;对于右端点,预处理出其到右边任意点的答案。于是对于跨越该分界线的询问 [L,R],设某个子区间为 [l,r],将左右答案 [L,l-1] 和 [r+1,R] 求和,再对每个子区间对应的答案取 max,就是该询问的答案。从而我们能够 O(m) 算出所有跨越区间中点的询问的答案。

这样的话我们需要预处理的时间复杂度为 T(n)=2\times T(\frac{n}{2})+O(n,m),初始状态为 T(m^{2})=O(m^{3})。又因为 T(n)=2\times T(\frac{n}{2})+O(n,m)<2\times T(\frac{n}{2})+O(n\sqrt{n}),故 T(n)\approx O(n\sqrt{n})。这样的话我们就把问题化归为 m\geq \sqrt{n}​ 的情况了(因为最后不能求解的区间的长度 \leq m^{2})。

  • Case 2:m\geq \sqrt n

下面进行二次分类讨论。

  1. 矩阵中存在一整行被询问区间包含,且这一行内没有任何数被选择。

枚举这一行是哪行,设这一行对应原序列的 [L,R]。容易发现这个整段的左右互不影响,答案为 f_{l,L-1}+f_{R+1,r}。因此,我们对每两行之间的分界点,向左向右预处理出到任意点的答案。预处理时间复杂度为 O(n \frac nm)\leq O(n\sqrt n)

  1. 矩阵中任意一个被询问区间包含的行都存在一个数被选择。

容易发现对于相邻两个被选择的数,它们在矩阵上的位置一定是后一个数在前一个数的右下方向。然后,将所有被选择的数依次连成一条折线。

我们在矩阵中间划一条竖线,它将每行分为长度为 [\frac m2], [\frac m2] 的两段,将第 i 行的后一段与第 (i+1) 行的前一段拼接,又能得到若干个长度为 m 的段,我们再次套用 1. 中的解法,相当于解决了折线越过我们所划的竖线的情况。

接下来需要解决折线不越过竖线的情况,那么如果在折线一边选了数,另一边就不能选数,在解决竖线一侧的问题时,另一侧的数完全无用。

若将一侧的元素顺次拼接,得到一个长度为原来的一半的序列,并认为 m 也随着矩阵宽度变化为原来的一半,解决一侧的问题相当于解决规模更小的原问题。

于是我们得到了两个规模更小的与原问题题意一致的子问题,n,m 均为原来的一半。若一个询问的最优解选择的第一个数与 l 或选择的最后一个数与 r 不在竖线的一侧,这种情况在之前套用 1. 中算法的时候已经计算过了,不需要递归,因此每个询问至多只会被递归到一个子问题中。

时间复杂度分析

预处理时间复杂度为 T(n)=O(n\sqrt n)+2T(\frac n2)T(n)=O(n\sqrt n)

每次询问时间复杂度为 T(n)=O(\sqrt n)+T(n/2)T(n)=O(\sqrt n)

总时间复杂度为 O((n+q)\sqrt n)

至此,我们在 O((n+q) \sqrt n) 的时间复杂度内解决了本题,采用离线整体二分的做法做到 O(n) 空间复杂度,即可通过本题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值