【学习笔记】slope-trick

敬请期待更多题目的到来()

[BalticOI 2004] Sequence (Day1)

\(f_{i,x}\) 表示考虑前 \(i\) 个位置,当前放了 \(x\)。转移式如下:

\[f_{i,x} = |a_i - x| + f_{i - 1,x} \]

考虑建坐标系,有点 $(x,f_{i,x})。然后它就相当于给当前的函数加上个 \(y=|a_i-x|\)

\[f_{i,x} = \min\{f_{i,x},f_{i,x-1}\} \]

注意到,我们每次加的是上凸函数,所以 \(f_i\) 也是上凸函数。因此想要实现上面这个转移,只需把斜率 >0 的地方抹平即可。

于是,上述过程可以用一个堆维护函数拐点。

P11678 [USACO25JAN] Watering the Plants P

\(f_{i,x}\) 表示使用前 \(i-1\) 个水渠,前 \(i-1\) 个植物都灌满了,第 \(i\) 个植物被灌了 \(x\) 单位水的方案数。

\[f_{i,x}=f_{i-1,w_{i-1} - x}+c_ix \]

\[f_{i,x}=\min\{f_{i,x},f_{i+1,x}\} \]

首先统一所有 \(x\) 的范围都是 \([0,10^6]\)

然后可以在坐标系上模拟 dp 过程,发现是个下凸函数。

具体操作是,把 \([0,w_{i-1}]\) 的函数翻转,然后把 \((w_{i-1},10^6]\) 的函数推平(都赋成 \(f_{w_{i-1}}\)),然后把斜率为负的前缀推平,最后再加上一个正比例函数。

考虑维护每段(\([0,1],[1,2],...\))的斜率!然后就是区间翻转+取反,区间覆盖成 0,区间加。平衡树即可。

可以令 \(c_1 = 2\times 10^6\) 来方便初始化。

Bonus:可以使用双端队列,元素为(区间,斜率),可以做到线性。

posted @ 2025-10-22 21:59  Aquizahv  阅读(4)  评论(0)    收藏  举报