劲爆会员制餐厅题
KingPowers · · 题解
Part 1. 确定 A 和 K 时的做法
我们先假设
假设选好了要为哪
假设确定为
这个式子其实可以写成:
所以初始令
以上的讨论都是基于
这个 DP 直接做是
发现比较烦人的是后面的
重新看下现在的式子:
这个形式可太熟悉了,一脸 slope trick 的感觉!容易归纳证明这个 DP 数组现在每一维都是下凸的了(现在不妨认为
当然我们还要支持前面的删去值不超过
- 初始时开一个小根堆
Q ,Q 内初始时只有一个元素\infty (因为除了f(0,0) 初值就应该是\infty ),并维护答案ans ,初始为0 。 -
扫描
i=1,2,\ldots,N ,扫到一个i 时,顺次执行以下操作:- 当
ans 加上堆顶元素不超过B_i 时,不断弹出堆顶元素并令ans 加上它。 - 将堆顶的元素减少
B_i-ans ,再将ans 赋值成B_i (也就是将差分数组第0 项变成B_i )。 - 将
A_i 加入堆中。
- 当
为了方便,可以再添加一个
答案是什么?根据前面的流程,我们每弹出一次堆顶(也就是在前缀删一个数)就能确定一个
因此当
值得一题的是直接从反悔贪心的角度好像也能得到上面的这一流程,限于本人水平暂时不展开篇幅。
Part 2. DP 计数
下一步就是对上面的 slope trick 的过程设计 DP 计数,类似题目有 AGC049E。
为了方便,我们规定当小根堆内有相同的数时,先加入堆的数更小,这样显然不会影响答案。
考虑直接用 DP 去维护上面的小根堆。看上去上面的过程其实很复杂,由于不可能做到记录堆里面目前有啥,所以好像也无法得知每次弹出的数具体是什么。但是我们可以直接钦定每个
转移个人觉得其实是容易的,但还是稍微展开讲一下。
首先考虑执行上面的弹出堆顶的操作,这里需要简单分类讨论下:
- 如果
ans\le b_i ,则我们之前钦定要被弹出的数在这里会全部被弹走,现在堆顶会剩下钦定没被弹的最小的数,它会减去B_i-ans 。所以此时执行l\leftarrow 0,r\leftarrow r-B_i+ans,ans\leftarrow B_i 。 - 否则说明之前钦定要被弹出的数在这里弹不完,要留到以后再弹,堆顶会有一个钦定被弹的数变成
ans-B_i 。所以此时执行l\leftarrow\min(l,ans-B_i) 即可。
现在得到了弹出堆顶后新的
直接实现上面的 DP 过程复杂度是
事实上本题可以做到
代码和其它题解基本差不多,就不放了。