学习草八牛。
AGC040E
致远 dp 入门题。
操作是给某个前缀加上一个不降非负序列,或者给某个后缀加上一个不升非负序列。考虑若只有一个操作(不妨是前者),此时的操作次数就是极长不降子段的数量。证明考虑这是一个显然的上界,同时观察到不可能一次缩掉两个段,因此这也是一个下界。对于第二个操作答案就是极长不升子段数量。
根据致远 dp,我们考虑两个操作分开处理,即拆分 \(a_i=p_i+q_i\),答案为 \(p_i\) 的不降子段数量加上 \(q_i\) 的不升子段数量。这很好设计 dp,\(f_{i,j}\) 代表令 \(p_i=j\) 后前 \(i\) 个数的答案,转移:
直接做是 \(O(n^2)\) 的,类似 slope trick(?),找一些这个 dp 的性质。首先对于某一个 \(f_i\),其本身具有单调性。同时有 \(f_{i,a_i}\le f_{i,0}+2\),因此直接维护 dp 取值相同的三段即可。时间复杂度 \(O(n)\)。
P4597
妄图通过这题简单认识 slope trick。
首先我们需要知道 slope trick 解决的问题中函数具有的性质:凸、连续、分段一次函数、斜率不大。接下来从这道题开始认识 slope trick。
首先一个暴力的 dp 是 \(f_{i,j}=\min\limits_{k\le j}f_{i-1,k}+|a_i-j|\)。\(f_i\) 是下凸的,这很好证,两个下凸的函数加起来还是下凸的,取 \(\min\) 操作只是将原来的下凸壳从最小值开始的斜率改成 \(0\)。对于这个下凸函数我们维护斜率的变化点,对于每条线段,我们在堆里放入若干个变化点的横坐标,使得线段的斜率是将变化点完全从堆里弹出次数的相反数。接下来的操作将围绕变化点进行,我们需要知道几件事实:
- 线段加上一个绝对值函数,若线段在顶点左侧则斜率 \(-1\),否则斜率 \(+1\)。
考虑 \(f_{i-1}\) 的下凸壳,以及最小值横坐标 \(op\)。考虑 \(f_i\) 的下凸壳形态:
-
\(a_i\ge op\),此时答案不会发生改变,同时前面的所有线段都应斜率 \(-1\),于是我们在堆中插入 \(a_i\)。归纳法可以证明 \(a_i\) 后面的斜率为 \(1\)。
-
\(a_i<op\),首先需要注意到该题的 \(f_i\) 中斜率的变化量总为 \(1\)(证明有点太难了吧)。后面感觉写不下去了,看 dwt 的吧!link。
CF1383E
找一些性质不难发现等价于可以删去原序列的一些数,其中一个极长全为 \(1\) 的段不能被删空,求能得到多少不同的序列。考虑判定,显然是前缀 \(0\) 匹配前缀 \(0\),后缀 \(0\) 匹配后缀 \(0\),同时对 \(1\) 的段做贪心匹配,在原序列上维护一个类似子序列自动机的东西即可。