Processing math: 6%
Alpha1022's Diaries
那儿,矛盾对立寂灭之处,即是涅槃。
挚爱的渴望之星,依然向我灼灼燃烧。
slope trick 题集
  1. 「CF713C」Sonya and Problem Wihtout a Legend
  2. 「ABC217H」Snuketoon
  3. 「CF1534G」A New Beginning
  4. 「ARC070E」NarrowRectangles
  5. 「CTSC2009」序列变换
  6. 「APIO2016」烟火表演
  7. 「CodeChef TREEBAL」Tree Balancing
  8. 「CF1229F」Mateusz and Escape Room
  9. 「CF280E」Sequence Transformation
  10. 「CF573E」Bear and Bowling
  11. 「USACO 2021.1 Platinum」Minimum Cost Paths
  12. 「BZOJ4877」跳伞求生
  13. 「CTSC2010」产品销售
  14. 「2018 ICPC World Finals」Conquer The World
  15. 「2023 Multi-University Training Contest 3」Teyberrs
  16. 「THUPC 2024 初赛」一棵树

前情提要:在「模拟费用流题集」中尝试坚持非 slope trick 的原生费用流做法,受阻。

顺便声明,笔者认为对凸函数维护折线的做法都属于 slope trick,而不区分维护方式。


「CF713C」Sonya and Problem Wihtout a Legend

典中典题。从经验倍数之多就可以看出:

  • 「洛谷 P4331」Sequence 数字序列
  • 「洛谷 P4597」序列 sequence
  • 「CF13C」Sequence
  • 「USACO 2008.2 Gold」Making the Grade

首先给 aiaii,然后问题限制变为不降。

我们有大力 DP fi(x) 表示操作了 1,,i,最后 aix 的最小次数。

考虑 fi1 转移到 fi 做的事:

  • 加上函数 |aix|

  • 做前缀 min

我们可以归纳证明 f_i(x) 是凸的:第一个操作是加上两段斜率为 \pm 1 的直线,第二个操作是把斜率 > 0 的部分砍掉。

证明的过程已经给出了算法:维护拐点的多重集,其中出现次数表示此处斜率变化的大小。注意到我们每次转移后永远在最后一段有斜率为 0,因此插入两个 a_{i+1} 后弹掉最大的拐点即可。


「ABC217H」Snuketoon

f_i(x) 表示经过 i 个事件,Snuke 在 x 点受到的最小伤害。

需要注意到我们有定义域 [-T_i, T_i]

转移是 f_i(x) = \min_{|x'-x| \le T_i-T_{i-1}} f_{i-1}(x')+ g_i(x),其中 g_i(x) 是一条射线。

我们将正负斜率部分分开维护,注意到区间 \min 相当于将两部分分别向左和右平移 T_i-T_{i-1} 单位,然后加一条不影响凸性的射线。


「CF1534G」A New Beginning

可以先将 Chebyshev 距离转 Manhattan,也可以不做。

考虑直接做 Chebyshev,显然恰好是 X+Y=x_i+y_i 的时候才会标记 (x_i, y_i)

f_k(x) 为走到了 (x, k-x),已经标记了所有 x_i+y_i \le k 的点的最小总能量。

转移是 f_k(x) = \min\{f_{k-1}(x-1), f_{k-1}(x)\} + g_k(x),其中 g_k(x) 是若干个 |x-x_i| 的和。

从而就是将斜率为正的部分向右平移 1 单位,然后加一些射线。


「ARC070E」NarrowRectangles

f_i(x) 表示操作了 1,\dots,i,最后 l_i=x 的最小代价。

转移是 f_i(x) = \min_{x-r_{i-1}+l_{i-1} \le x' \le x+r_i-l_i} f_i(x') + |l_i-x|

仍然是分斜率正负的平移,然后加两条射线。


「CTSC2009」序列变换

和前面的题差不多,但是它限制了定义域,所以在截取的时候可能需要将谷底平移并修改维护的答案,实现较为麻烦。

也可以直接构造方案然后求答案。


「APIO2016」烟火表演

f_u(x) 表示操作了 u 的子树,其中所有叶子到 u 的距离均为 x 的最小代价。

考虑转移是 f_u(x) = \sum_v \min_{x'\le x} \{f_v(x') + |x-x'-w|\},其中 \sum_v 通常是容易的,\min_{x'}f_v(x)|x-w| 做 Minkowski 和。

将斜率归并,那么 <0 的斜率依然在最前面,<0=0 之间会插入一条横向长度为 w,斜率为 -1 的直线,>0 的直线会被删除并直接加入一条斜率为 1 的直线。

用可并堆维护即可。


「CodeChef TREEBAL」Tree Balancing

上一题的加强版。现在有费用 c_i 并且可以改成负数,相当于丢掉所有斜率绝对值超过 c_i 的拐点,然后整体向右平移 w_i 单位。

需要使用平衡树维护。


「CF1229F」Mateusz and Escape Room

三分 n,0 之间传递的流量,然后使用 slope trick。

转移也是平移,现在我们要查询特定点的值,显然也只需从谷值开始计算贡献。


「CF280E」Sequence Transformation

和先前的题区别是费用变成了二次函数,那么我们需要在差分数组上增加一个一次函数。

需要用平衡树维护。


「CF573E」Bear and Bowling

f_i(x) 表示前 i 个数选了 x 个的最大答案,有转移 f_i(x) = \max\{f_{i-1}(x), f_{i-1}(x-1)+a_i x\}

归纳证明凸性。考虑转移,选择后者当且仅当某一处 f_{i-1}(x) - f_{i-1}(x-1) < a_i x。根据归纳假设,这一部分是凸的。因此转移就是在差分数组中找到第一个需要选择后者的位置 x',插入一个 a_i x' 并将后面的部分加上 x'

用平衡树维护。


「USACO 2021.1 Platinum」Minimum Cost Paths

f_y(x) 表示走到 (x, y) 的最小代价。转移是首先加上 x^2,然后在差分数组中插入一个 c_y

其实这就是 L_2 保序回归,这个做法跟单调栈做法本质相同。


「BZOJ4877」跳伞求生

老鼠进洞!

f_i(x) 表示前 i 个点,有 x 组匹配要经过 (i, i+1) 的最大费用。

如果是一个费用为 w 的老鼠,那么转移是 f_i(x) = \max\{f_{i-1}(x), f_{i-1}(x-1)+w\}。相当于在差分数组中插入一个 w

如果是一个费用为 w 的洞,那么转移是 f_i(x) = \max\{f_{i-1}(x), f_{i-1}(x+1)+w\}。相当于将差分数组中第一个位置删除并插入一个 -w

其实跟反悔贪心一模一样。


「CTSC2010」产品销售

注意方向不同的匹配必然不会相交,方向相同的匹配是否相交并不重要,我们只关心流量。

f_i(x) 表示最终 (i, i+1) 的流量为 x(若 x<0 表示向左流),1,\dots,i+1 之间的边的最小总费用。由费用流建模,可以证明其 \ge 0\le 0 部分均是凸的。

设其差分数组

g_i(x) = \begin{cases} f_i(x)-f_i(x-1), &x>0\\ 0, &x=0 \\ f_i(x)-f_i(x+1), &x<0 \end{cases}

另设辅助函数

h_i(x) = \begin{cases} -M_i x, & x > 0 \\ 0, & x = 0 \\ C_i x, & x < 0 \end{cases}

则也可证明 (f_i+h_i)(x) 整体是凸的,因为这等价于删除 (i, i+1) 的费用。

首先考虑从 i-1i,我们需要

f_i(x) = \begin{cases} f_{i-1}(x) + M_i x, & x>0 \\ f_{i-1}(0), & x=0 \\ f_{i-1}(x) - C_i x, & x<0 \end{cases}

这就是差分数组的整体加。

考虑现在 i 处加入了一条入边,有转移

f_i'(x) = \begin{cases} \min\{f_i(x), f_i(x-1)+P_i+M_i\}, & x>0 \\ \min\{f_i(x), f_i(x-1)+P_i-C_i\}, & x\le 0 \end{cases}

然后令 f_i(x) \gets f_i'(x)

g_i(-1) \ge C_i-P_i,则 g_ix < 0 部分不变,x > 0 部分等价于插入 P_i+M_i

g_i(-1) < C_i-P_i,则对于 x < 0 部分等价于删除 g_i(-1) 后插入 C_i-P_i。对于 x > 0 部分,f_i'(0)=f_i(0)+g_i(-1)+P_i-C_i,而由 (f_i+h_i)(x) 的凸性(容易说明完成转移之前也是凸的),有 f_i(0)-f_i(-1)+C_i \le f_i(1)-f_i(0)-M_if_i(1) \ge f_i(0) + M_i + C_i - g_i(-1) > f_i(0) + M_i + P_i,因此 f_i'(1) = f_i(0) + M_i + P_i,且 g_i'(1)=-g_i(-1)+M_i+C_i。因而相当于在 x>0 部分插入 -g_i(-1)+M_i+C_i

要支持批量加入与删除,需要使用平衡树维护。


「2018 ICPC World Finals」Conquer The World

注意到子树的合并即 Minkowski 和,使用可并堆维护即可。


「2023 Multi-University Training Contest 3」Teyberrs

细节比较多,但总体来说还是先前的基本操作的组合。

此题可以用线段树维护。


「THUPC 2024 初赛」一棵树

双倍经验:「Yuhao Du Contest 7」Cyclic Distance。

f_u(x) 表示 u 子树内选 x 个黑点的答案。合并是 Minkowski。

标算是维护两部分可并堆,但是 Treap / Splay 等能支持在树上 O(n\log n) 合并的平衡树常数足够优秀也可以通过。