E

E. MEX and Increments
题目大意
给你一个数组 aa,数组整体求 mex\text{mex},分别求出 mex={0,1,2,,n}\text{mex} = \{0, 1, 2, \cdots, n\} 时候
需要修改几次 aa 数组?每一次修改操作定义为,将任意位置元素 ajaj+1a_j \leftarrow a_j + 1

分析 mex\text{mex} 问题,一般是要翻译一下
不难想到对整个数组 aa 求一下 cnt(ai)cnt(a_i),即每个元素出现次数
mex=x\text{mex} = xx[1n]\forall x \in [1\cdots n]

  • ans(x)\text{ans}(x) 有解的情况,当且仅当 [0x1][0\cdots x-1] 所有数都要出现,此时 cntcnt 对应的前缀和 sum(x1)xsum(x-1) \geqslant x 才有解
    进一步分析,因为只能 ajaj+1a_j \leftarrow a_j + 1,也就是说,令 yy[0x1][0\cdots x-1] 中空缺的数
    yy 只能由 <y< y 的数来补全,必然有 y<xy < x
    如果这些数连 mex=x\text{mex} = x 的空缺都填不上,对于 x+1,x+2,x+1, x+2, \cdots 更填不上了
    所以如果找到一个位置 ans(x)=1ans(x) = -1,对于 x+1,x+2,x+1, x+2, \cdotsansans 的值均为 1-1
  • 有解的话,可以考虑 dp\text{dp}dp(x)dp(x) 表示 {0,1,,x1}\{0, 1, \cdots, x-1\} 全部都出现,所需要的代价
    dp(0)=0dp(0) = 0ans(x)=dp(x)+cnt(x)\text{ans}(x) = dp(x) + cnt(x)
    即在 {0,1,,x1}\{0, 1, \cdots , x-1\} 都出现的基础上,让 xx+1x \leftarrow x + 1,此时 xx 就不会出现
  • 然后考虑 dp(x)dp(x+1)dp(x) \to dp(x+1) 的转移,转移的代价就是需要补上空缺 xx 的代价
    如果 cnt(x)=0cnt(x) = 0,那么原序列就没有 xx,那么需要找到 y[0x1]y \in [0\cdots x-1] 这些数中,找到满足
    cnt(y)2cnt(y) \geqslant 2 的最大的那个数 yy,这可以边扫描边维护一个栈实现
    栈中只保留 cnt2cnt \geqslant 2 的数,如果找不到,那么 ans(x+1,x+2,n)=1ans(x+1, x+2, \cdots n) = -1
    否则的话,dp(x+1)=dp(x)+xydp(x+1) = dp(x) + |x - y|,并且要记得更新 cnt(x)++,cnt(y)cnt(x)++, cnt(y)--
  • 如果 cnt(x)>0cnt(x) > 0,那么原序列已经有 xx 了,不需要额外补全元素,dp(x+1)=dp(x)dp(x+1) = dp(x)
    记得如果 cnt(x)2cnt(x) \geqslant 2 的时候,将其放入栈中

一些区间有关的套路

多路归并

K 个最小和
给定 kk 个整数数组,包含 kk 个元素,在每一个数组中取出一个元素加起来,可以得到 kkk^k 种不同的元素
求这些元素中最小的 kk 个值

先考虑下面的问题,合并两个长度为 nn 的数组 A,BA, B,得到一个长度为 nn 的数组 CC
合并的过程是任意取 A,BA, B 中的元素,可以得到 n2n^2 个和,求这些和中最小的 nn 个,作为 CC 数组

首先先令 A,BA, B 均有序,实际上,对于有序数组,可以得到一张表

{A1+B1A1+B2+A1+BnA2+B1A2+B2+A2+BnAn+B1An+B2+An+Bn\begin{cases} A_1 + B_1 \leqslant A_1 + B_2 + \leqslant \cdots \leqslant A_1 + B_n \\ A_2 + B_1 \leqslant A_2 + B_2 + \leqslant \cdots \leqslant A_2 + B_n \\ \cdots \\ A_n + B_1 \leqslant A_n + B_2 + \leqslant \cdots \leqslant A_n + B_n \end{cases}

那么最小的一个元素,必然包含在 {A1+B1,A2+B1+An+B1}\{A_1+B_1, A_2+B_1 + \cdots A_n+B_1\} 之中
考虑使用优先队列,维护一个二元组 (sum,j)(sum, j),其中 sum=Ai+Bjsum = A_i + B_j
一开始的时候,对于每一个 Ai, i[1,n]A_i, \ i \in [1, n](sum,b)(Ai+B1,1)(sum, b) \leftarrow (A_i+B_1, 1) 放入优先队列
然后动态地遍历 j[1,n]j \in [1, n],每一次取堆顶元素 C[j]top.sumC[j] \leftarrow \text{top}.sumbtop.bb \leftarrow \text{top}.b
之后动态维护 (sum,b)(sumB[b]+B[b+1],b+1)(sum, b) \longrightarrow (sum - B[b]+B[b+1], b+1)

kk 路归并,实际上就是把之后的数组,合并到已经处理过的数组即可
另外需注意,假设我们检查了 (Ai+Bj)(A_i + B_j) 是第 mm 小,接下来要考虑 (Ai+Bj+1)(A_i + B_{j+1}) 是不是第 m+1m+1
所以要维护一个 BB 相应的下标 bb,因为 Bb+1B_{b+1} 可能作为要检查的候选值,放入优先队列中

动态连续和问题

UVA1400
给定一个数组 DD,对 mm 个问询 (a,b)(a, b) 做出回答,需要找到 axyba \leqslant x \leqslant y \leqslant b(x,y)(x, y)
使得 Dx+Dx+1++DyD_x + D_{x+1} + \cdots + D_{y} 尽量大,如果有多组满足条件,那么 xx 尽量小,如果还有多解 yy 应尽量小

不难想到使用线段树,具体来说,对于某个节点 pp,要维护的是
prepre,表示 p.lprep.rp.l \leqslant pre \leqslant p.r,并且 S[p.l,pre]S[p.l, pre] 区间和最大
换句话说,prepre 表示从 p.lp.l 往前最远能扩展到哪里
sufsuf 表示 p.rp.r 往左边最远能扩展到的位置,这里扩展的意思是,使得 S[suf,p.r]S[suf, p.r] 区间和最大
subsub 用一个二元组 (x,y)(x, y) 表示,满足 p.lxyp.rp.l \leqslant x \leqslant y \leqslant p.r 并且 S[x,y]S[x, y] 最大

维护好这些信息之后,考虑 pull\textbf{pull} 操作,不妨设 pp 的两个子节点分别为 pl,prpl, pr
根据题目要求,定义一个 max(seg1,seg2)\max(seg1, seg2) 操作,如果 S(seg1)S(seg2)S(seg1) \neq S(seg2),那么取区间和 SS 较大的那一段
否则如果 seg1.xseg2.xseg1.x \neq seg2.x,取 xx 较小的,xx 仍然相同的话,取 yy 较小的

  • 对于 p.prep.pre,如果 S[pl.l,pl.pre]S[pl.l,pr.pre]S[pl.l, pl.pre] \geqslant S[pl.l, pr.pre],那么 p.prepl.prep.pre \leftarrow pl.pre
    否则的话,p.prepr.prep.pre \leftarrow pr.pre
  • 对于 p.sufp.suf,如果 S[pr.suf,pr.r]>S[pl.suf,pr.r]S[pr.suf, pr.r] > S[pl.suf, pr.r],(因为如果相等的话,要取尽量靠左的),p.sufpr.sufp.suf \leftarrow pr.suf
    否则的话,如果有 S[pl.suf,pr.r]S[pr.suf,pr.r]S[pl.suf, pr.r] \geqslant S[pr.suf, pr.r]p.sufpl.sufp.suf \leftarrow pl.suf
  • 接下来考虑 p.subp.sub 对应的二元组如何求,实际上,p.subp.sub 是以下几段的最大值
    max{[pl.sub.x],[pr.sub],[pl.sufpr.pre]}\max\{\quad [pl.sub.x], [pr.sub],[pl.suf \cdots pr.pre] \quad\}
    用上面定义个 max\text{max} 操作,求出最大的区间 [x,y][x, y] 即可

下面考虑问询 (a,b)(a, b)
如果找到了 (a,b)(a, b) 对应的区间 pp,直接返回 p.subp.sub
没找到的话,如果 bp.midb \leqslant p.\text{mid},只需要递归左子区间,a>p.mida > p.\text{mid},只需要右子区间
否则同时递归左子区间和右子区间,答案有三段构成
max{[pl.sub],[pr.sub],[pl.suf,pr.pre]}\max\{ [pl.sub], [pr.sub], [pl.suf, pr.pre] \},其中 pl.subpl.subpr.subpr.sub 都可以直接通过递归来返回
递归若返回的是区间 [x,y][x, y],如何获取 suf,presuf, pre 等信息?
这里我们令递归返回的是 node\textbf{node} 结点,如果同时递归左右子树,那么就新开一个结点 tmptmp
结点的 sub,pre,sufsub, pre, suf 信息按照如上所述更新即可,返回 tmptmp
具体来说可以复用 tmppull(node(l),node(r))tmp \leftarrow \textbf{pull}(\text{node(l)}, \text{node(r)}) 函数
按照之前定义的 pull\textbf{pull} 规则来合并左右子节点,并返回

滑动窗口杂题

最小覆盖子串

这是一个连续字串的问题,很自然地想到滑动窗口
不难想到,用 cnt\textbf{cnt} 这个 map\text{map} 来维护滑动窗口中字符出现的次数
mp\text{mp} 预处理出 TT 中字符出现的次数,那么就可以写出 check()\text{check}() 函数了

首先能想到的思路是,一开始令两个指针 i=0,j=0i = 0, j = 0,滑动窗口为 [i,j][i, j]
遍历 i[0,ni \in [0, n),对每一个 ii,令 jij \leftarrow i
while check()=false\textbf{while} \ \text{check()} = \text{false},那么就令 jj+1j\leftarrow j+1,同时更新 cnt\textbf{cnt}
这样当 while\textbf{while} 循环执行完之后,[i,j][i, j] 就是满足条件的,用来更新答案即可
下面问题来了,jj 确定下来了,ii 接下来要怎么走?i=i+1,i+2,i = i+1, i+2, \cdots
这样对于每一个 jj,当 ii 处出现冗余的时候,[i,i+1,,j1][i, i+1, \cdots, j-1] 这么多可能都是冗余的,这样时间复杂度是 O(n2)O(n^2)

所以要换一个思路,产生上述情况的原因是
[i,i+1,i+2,)[i, i+1, i+2, \cdots) 一定缺少了某个元素,这个元素在 jj 处才被找到
此时 [i,i+1,i+2,)[i, i+1, i+2, \cdots) 可能会出现冗余元素,基于此,可以设计出如下算法
开始时令 i=0,j=0i = 0, j = 0,并且 ii 先不去动它,令 j[0,n)j \in [0, n) 遍历
while check()=1\textbf{while} \ \text{check}() = 1,就说明 [i,j][i, j] 合法,先更新答案,然后不断删除 ii 开始的前缀冗余元素
ii+1i \leftarrow i+1,同时更新 cnt\textbf{cnt},这样当 while\textbf{while} 循环结束之后
[i,j][i, j] 又变成了删除冗余元素之后,不满足条件的区间,jj 又可以接着往前走了
这样不仅不会漏解,时间复杂度还可以保证是 O(n)O(n)

唯一的雪花
给定一个序列 AA,找一个尽量长的连续子序列 A[l,r]A[l, r],使得序列中没有相同元素
这个问题和之前的问题的区别在于,这一次是尽量长

不难想到用滑动窗口,并且用一个 set\textbf{set} 维护滑动窗口中的元素
开始时候令 i=0,j=0i = 0, j = 0先不去动 ii,那么 jj 能往前走的充要条件是,set(Aj)=\textbf{set}(A_j) = \emptyset
题中要求尽量长,对于起点在 ii 位置的窗口,先不去动 ii,用一个 while\textbf{while} 循环
只要 set(Aj)=\textbf{set}(A_j) = \emptyset,就把 AjA_j 放入集合中,并且令 jj 往前走
这样 while\textbf{while} 循环结束后,[i,j)[i, j) 就是以 ii 作为起点,最长的满足条件的滑动窗口,用 jij-i 更新答案

接下来呢? ii+1i \leftarrow i+1 往前走,同时维护 set\textbf{set} 删除 AiA_i,相当于更新窗口起点
重复以上算法即可,因为 [i,j)[i, j) 没有冗余元素,[i+1,j)[i+1, j) 也不会有冗余元素,所以 ii 一定在 jj 后面
扫描的时间复杂度是 O(n)O(n),加上 set\textbf{set} 的维护,总时间复杂度是 O(nlogn)O(n\log n)

shuffle的播放记录
播放器中有 ss 首歌,一开始这些歌会随机排序,全部播放完之后再随机排序,给出一个长度为 nn 的播放记录 xix_i
不一定从最开始记录,其中 1xis1 \leqslant x_i \leqslant s,那么请问下一次随机排序发生的位置有多少种可能?
就是问,下一次随机排序的位置,可能是 [1,2,,s][1, 2, \cdots, s],这中间有几种是合法的呢?

这是一个确定窗口长度的滑动窗口问题,滑动窗口位置为 [i,i+s1][i, i+s-1],不难想到如下动态维护的算法
tottot 维护滑动窗口中有几个不同的元素,这样窗口滑动的时候,维护过程如下
if cnt(Ai)=0\textbf{if}\ --\text{cnt}(A_i) = 0tottot--if ++cnt(Ai+s)=1\textbf{if} \ ++\text{cnt}(A_{i+s}) = 1tot++tot++then i++\textbf{then}\ i++

那么算法大致执行流程如下,枚举随机播放的位置,i[0,s1]i \in [0, s-1],作为滑动窗口的起点
通过预处理判断每一个位置是否是合法起点ii 能成为答案的充要条件是
{i,i+s,i+2s,}\{i, i+s, i+2s, \cdots \} 都是滑动窗口的合法起点
预处理判断的过程也很简单,检查序列位置 [i,i+s1][i, i+s-1],如果此时滑动窗口的 tot=stot = sii 就是合法起点

算法的主过程大致如此,问题是,可能存在不完整的窗口,怎么办呢?可以在序列前后补 00
[0s1][ss+n1][s+nn+2s1][0\cdots s-1] \cup [s\cdots s+n-1] \cup [s+n \cdots n+2s-1]
这样把原序列放在 [ss+n1][s\cdots s+n-1] 中,前后补 00,滑动窗口的起点从 00 开始,为了处理边界,加入哨兵结点
也就是说,一开始的时候滑动窗口在 [0,s1][0, s-1] 这个位置,此时 tot=0tot = 0,滑动窗口还没有开始检查序列
此时状态也被认为是合法状态,对于不完整的段
is1i \leqslant s-1,如果此时 (i+s1)s+1=tot(i+s-1)-s+1 = tot,那么 ii 合法
i+s1s+ni+s-1 \geqslant s+n,如果此时 s+n1(i)+1=tots+n-1-(i)+1 = tot,那么 ii 合法
因为加入了补 00 的段,窗口滑动的时候,注意 if Ai0\textbf{if} \ A_i \neq 0 才执行 cnt(Ai)=0--\text{cnt}(A_i) = 0 的判断

另外注意特判,sn+1s \geqslant n+1,此时播放记录中的 nn 首歌,只是所有歌单 ss 中的一段,不是完整的歌单
那么下一次随机播放的位置,可以是 ss 首歌单中的任意一首,答案为 ss

单调性优化杂题

防线
给定一个长度为 nn 的序列,删除一个连续子序列,使得剩下的序列中有一个长度最大的,连续的,严格递增的子序列
换句话说,就是要在 AA 中找到 [i,j][i, j]ii 往左扩展得到最长的连续递减序列长度为 dp1(i)dp1(i)
jj 往右扩展得到最长的连续递增序列长度为 dp2(j)dp2(j),我们要找到 dp1(i)+dp2(j)dp1(i) + dp2(j) 最大

首先,令 dp1(i)dp1(i) 表示以 ii 结尾的最长连续递增序列的长度
dp2(i)dp2(i) 表示从 ii 开始,以 ii 起始的最长连续递增序列的长度,这都可以通过扫描预处理得到

对于某一个 iii[1,n]i \in [1, n],先固定 ii 不动,对于此时的 dp2(i)dp2(i)
要从已扫描过的序列 j[1,i1]j \in [1, i-1] 中找到 dp1(j)dp1(j) 最大的,即 maxj[1,i1]dp1(j)\displaystyle\max_{j \in [1, i-1]} dp1(j),此外还要保证 Aj<AiA_j < A_i

(maxj[1,i1]dp1(j))\left(\displaystyle\max_{j \in [1, i-1]} dp1(j)\right) 第一反应是用单调栈维护
但很可惜这里不能单调栈,原因是我们需要的答案是 maxi(dp2(i)+maxj[1,i1]dp1(j){Aj<Ai})\displaystyle\max_{i} \left(dp2(i) + \max_{j \in [1, i-1]} dp1(j) \Big| \{A_j < A_i\}\right)

如果用严格单调递增的栈来维护 maxj[1,i1]dp1(j)\displaystyle\max_{j \in [1, i-1]} dp1(j),对于 ii,将 dp1(i)dp1(i) 入栈之前
我们需要扔掉栈中满足 xdp1(i)x \geqslant dp1(i) 的元素,
而这些元素很可能会和 dp2(i+1,i+2,)dp2(i+1, i+2, \cdots) 构成更优解,但我们把它扔掉了,就丢失了最优解

那我们不要把它扔掉不就可以了?
对于 j[1,i1]j \in [1, i-1],一定是 dp1(j)dp1(j) 越大越好,同时 A(j)A(j) 越小越好
基于此来优化,对于 dp1(j1)<dp1(j2)dp1(j1) < dp1(j2) 并且 A(j1)A(j2)A(j1) \geqslant A(j2)j1j1 是无用解

那么候选集合 j[1,i1]j \in [1, i-1] 一定是

{A(j1)<A(j2)<<A(jk)dp1(j1)<dp1(j2)<<dp1(jk)\begin{cases} &A(j1) < A(j2) < \cdots < A(jk) \\ &dp1(j1) < dp1(j2) < \cdots < dp1(jk) \end{cases}

那问题就简单了,用一个 set\textbf{set} 维护二元组 (A(j),dp1(j))(A(j), dp1(j)),按 A(j)A(j) 排序
对于每一个位置 iidp1(j),j[1,i1]dp1(j), j \in [1, i-1] 最大的位置,一定是最右边的满足 A(j)<A(i)A(j) < A(i) 的位置
可以在 set\textbf{set} 中二分查找到这个位置 kk,然后用 dp1(k)+dp2(i)dp1(k) + dp2(i) 来更新答案

接下来考虑如何去维护? 假设当前的二元组为 cur=(A(i),dp1(i))cur = (A(i), dp1(i))curcur 按道理说应该插入 set\textbf{set}k+1k+1
根据上面分析,如果 dp1(set(k))dp1(i)dp1(\textbf{set}(k)) \geqslant dp1(i),那么 curcur 不应该插入 k+1k+1

否则的话,在 set\textbf{set} 中插入 cur=(A(i),dp1(i))\text{cur} = (A(i), dp1(i)),插入的时候注意判断一下
如果 set\textbf{set} 中有第一关键字等于 A(i)A(i) 的元素,就把它删掉,保证候选集合中 AA 是严格单调的
然后找到 curcurset\textbf{set} 中的位置 pp,检查 p=(p+1,p+2,)p' = (p+1, p+2, \cdots )
如果 A(set(p))>A(cur)A(\textbf{set}(p')) > A(cur) 并且 dp1(set(p))dp1(cur)dp1(\textbf{set}(p')) \leqslant dp1(cur)
就在 set\textbf{set} 中删掉 pp'

裁剪序列
题目大意,给定一个长度为 nn 的序列 aa,将其分为若干段,满足每一段所有数的和 M\leqslant M
还要满足取每一段所有数的最大值,然后这些最大值求和,要使得这些最大值之和最小

考虑 dpdp,用 dp(i)dp(i) 表示 [1i][1\cdots i] 这些数分成若干段,满足每一段的和 M\leqslant M 并且
每一段数的最大值的和能取到的最小值,状态转移方程如下

dp(i)=min1j<i(dp(j)+(maxk[j+1,i]Ak){k[j+1,i]AkM})dp(i) = \min_{1 \leqslant j < i} \left(dp(j) + \left(\max_{k \in [j+1, i]}A_k \right)\Big| \left\{\sum_{k \in [j+1, i]} A_k \leqslant M\right\}\right)

本例的限制条件为 k[j+1,i]AkM\displaystyle\sum_{k \in [j+1, i]}A_k \leqslant M,并且要取 [j+1,i][j+1, i] 区间内的最大值 maxAk\max A_k
那么能够成为候选值AjA_j 一般是有单调性的

  • 因为 maxk[j+1,i]Ak\max_{k \in [j+1, i]} A_k 非负,所以 dp(j)dp(j) 非严格单调递增,也就是说,如果要让 dp(j)dp(j) 尽量小的话
    jj 应该要尽可能靠左,也就是说,满足 [j,i]M\sum [j, i] \leqslant M 的最左边的那个 jj,对应的 dp(j1)dp(j-1) 是满足条件最小的 dpdp
    首先有取值 dp(i)dp(j1)+maxA[j,i]dp(i) \leftarrow dp(j-1) + \max A[j, i]
  • 我们需要的是 min(dp(j)+maxA[j+1,i])\min\left(dp(j) + \displaystyle\max A[j+1, i]\right),这部分的值没有单调性
    dp(j)dp(j) 最小并不能够使得 dp(j)+Akdp(j)+ A_k 最小,考虑 dpdp 增大,AkA_k 减小的时候,值也会动态变化
    在找到 [j,i]M\sum[j, i] \leqslant M 这个约束条件之后,还要用二叉堆维护可能的候选值 {j,j+1,,i}\{j, j+1, \cdots, i\}
    可能的候选值是如何变化的呢?
    不难发现,[j,i]M\sum [j, i] \leqslant M,对于某一个 ii 而言,jj 一定越靠近 ii 越好,同时 AjA_j 越大越好
    j1<j2j1 < j2,如果 A(j1)A(j2)A(j1) \leqslant A(j2),那么 j1j1 就是无用的解

{j1<j2<<jkA(j1)>A(j2)>>A(jk)dp(j)非严格单调增\begin{cases} &j1 < j2 < \cdots < jk \\ &A(j1) > A(j2) > \cdots > A(jk) \\ &\text{dp}(j) \text{非严格单调增} \end{cases}

基于以上分析,可以设计出如下算法,对于当前的 ii
用单调队列维护动态变化的候选值 AjA_jAjA_j 的意义是,存在 [p,i][p, i] 区间以 AjA_j 作为最大值pp 应该取多少?
应该使得 dp(p)dp(p) 越小越好,即满足约束条件的情况下,pp 尽量靠左
不妨设左边第一个比 AjA_j 大的元素位置是 le(j)le(j),那么 p=le(j)+1p = \text{le}(j) + 1
实际上,单调队列维护的候选值 {j1,j2,,jk}\{j1, j2, \cdots, jk\},左边第一个比 A(j2)A(j2) 大的元素就是 A(j1)A(j1),以此类推
所以 j2j2 在二叉堆中对应的值为 dp(j1)+maxA[j1+1i1]=dp(j1)+A(j2)dp(j1) + \max A[j1+1 \cdots i-1] = dp(j1) + A(j2)
注意,根据以上分析,A[j1+1i1]A[j1+1\cdots i-1] 都是以 A(j2)A(j2) 作为最大值的

我们要在单调队列中插入 A(i)A(i),首先维护队尾元素的单调性
que[,r3,r2,r1]\text{que}[\cdots, r3, r2, r1],我们有 A(que[r3])>A(que[r2])>A(que[r1])A(\text{que}[r3]) > A(\text{que}[r2]) > A(\text{que}[r1])
如果 que[r1]A(i)\text{que}[r1] \leqslant A(i),那么要删除 que[r1]\text{que}[r1],这个元素在二叉堆中对应的值为
dp(que[r2])+maxA(que[r2]+1,i1)=dp(que[r2])+A[que[r1]]dp(\text{que}[r2]) + \max A(\text{que}[r2]+1, \cdots i-1) = dp(\text{que}[r2]) + A[\text{que}[r1]],也要相应地删掉

然后尝试加入 A(i)A(i),同时在二叉堆中加入 dp(que[r])+maxA[que[r]+1i]=dp(que[r])+A(i)dp(\text{que}[r]) + \max A[\text{que}[r]+1 \cdots i] = dp(\text{que}[r]) + A(i)
这样就完成了维护

这样我们就维护出了 dp(j)dp(j) 动态增加,AkA_k 动态减少时候的最小值,取二叉堆堆顶元素即可
二叉堆维护的是动态变化时候,可能的 AkA_k 值,我们还需要知道 dp(j)dp(j) 最小可能取多少?
考虑限制条件
用一个滑动窗口,维护最左边满足 A[pi]M\sum A[p\cdots i] \leqslant Mpp 值,此时
dp(i)=min(dp(i),dp(p1)+maxA[pi])dp(i) = \min(dp(i), dp(p-1) + \max A[p\cdots i]) 对应的 dp(p1)dp(p-1) 是满足约束条件的最小值

另外,考虑限制,需要检查一下队首元素 que[l1,l2,]\text{que}[l1, l2, \cdots]
如果 que[l]<p\text{que}[l] < p,那么需要删除 que[l]\text{que}[l]
同时,二叉堆中对应的 dp(que[l1])+maxA[que[l1]+1i]=dp(que[l1])+A(que[l2])dp(\text{que}[l1]) + \max A[\text{que}[l1]+1 \cdots i] = dp(\text{que}[l1]) + A(\text{que}[l2]) 取不到了
也对应地删除,另外不难发现,此时 maxA[pi]\max A[p\cdots i] 就是我们维护的 que[l]\text{que}[l]
这里取 dp[i]min(dp(p1)+que[l], 二叉堆的最小值)dp[i] \leftarrow \min(dp(p-1) + \text{que}[l], \ \text{二叉堆的最小值}) 就是答案