DP1
1.Minimum Sum of Maximums P
首先这个 \(\sum_{i=1}^{n-1}\max(a_i,a_{i+1})\) 不太好描述,我们把他变成 \(\sum_{i=1}^{n-1} \frac{a_i+a_{i+1}+|a_i-a_{i+1}|}{2}\),我们可以发现除了两边放的值所有值都会先算两遍,我们可以通过先往左右两边先加入一个 \(+\infty\)。这样就只用考虑绝对值的贡献。
对于区间 \(i\) 的端点设为 \(L_i,R_i\)。
我们可以对于所有确定了两端值的区间中间插入一些值。通过一些调整我们可以知道对于一段区间中我们一定会把数顺序或逆序插入,我们会把小的数对应端点小的那一边。设插入的数的最大值为 \(mx\),最小值为 \(mn\)。那么一段区间的贡献即为 \(\sum_{i=1}^{i=k} mx-mn+|mx-R_i|+|mn-L_i|\)。
寻找一些性质,我们发现这些区间中的值域区间一定没有相交关系。
使用反证法:
若存在相交,\(l_i<l_j<r_i<r_j\)。
\(v=(mx+|mx-r_i|)+(-mn+|mn-l_i|)\)
我们发现权值在 \(mx\) 减小一定不劣,将 \(mn\) 增大同样不劣,如此可以证明。
现在权值之间只有包含或不交关系。我们可以对于值域进行区间 DP。
我们有三个操作:
- 扩大区间。
- 合并两个区间
- 在一个区间中间插入一个区间,并钦定左右两个端点是值域的两个端点。
我们可以区间 DP解决,复杂度 \(O(n^2 \times 3^k)\)。
2.摩卡串
考虑每次往后缀加一个字符的贡献,我们只需要记下答案已经有多少了,当前有多少后缀与前缀相同,有多少子串已经比前缀小了,长度为多少。
答案可以直接更新,每次加一个字符,更新有多少后缀与前缀相同,这个你直接建 kmp 自动机直接跳,已经有多少子串比前缀小也可以直接更新,长度可以直接更新。
这个直接做就是 \(O(n^3 k)\),考虑怎么优化一下,我们发现如果后面状态相同只有长度不同,这种状态不优,完全不用访问,用 \(bfs\) 逐层转移即可可以降到 \(O(n^2 k)\)。
再分析一下有多少子串已经比前缀小这个最大只会到 \(\sqrt k\),那么这样直接写就是 \(O(n k^{1.5})\)。
3.Two Airlines
我们首先显然可以写出一个 \(O(n^3)\) 暴力表示已经到了前 \(i\) 个位置,用了前 \(j\) 个 \(A\) 公司的人, \(k\) 个 \(J\) 公司的人,每次直接转移就是 \(O(n^3)\) 的。
这个状态都不对,无法通过。
这样设状态显然无法通过的,我们考虑改写一下状态表示已经用了当前位置后 \(j\) 个 \(A\) 公司的人, \(k\) 个 \(J\) 公司的人,这样状态看似是 \(O(n^3)\),实际上是 \(O(n \log^2 n)\)。
我们考虑证明一下。
偷了一张图过来,这种图就是,每个位置都有一个红色点,然后很远后面一堆蓝色点。
显然这样的图一定会使用最多后面的人。

我们考虑如果把最上面蓝点删掉会怎么样。
设从左往右的红色线段中的红色节点个数分别为 \(w_1,w_2...w_k\)
此时我们发现如果不要最后一个人的话,贡献为 \(\sum_{i=2}^{k} w_i +2 w_1\),否则贡献为 \(\sum_{i=2}^{i=k} 2w_i +w_1\),由此我们发现若是想要加入后最优一定要有 \(w_1 \gt \sum_{i=2}^{k} w_i\),此时和翻倍,于是最多只有 \(\log n\) 个。
直接做就可以做到 \(O(n \log ^2 n)\)。
4.Doors and Keys
首先有个明显答案的上界为 \(n+V\),即为你等到门开完直接冲过去。
我们可以得到一个 \(O(n^2)\) 的暴力 DP 做法,即为设要拿多少把钥匙走到下一扇门,我以发现,一但我们想要带 \(x\) 把钥匙走到下一个门,我们一定是先把所有钥匙挪动到当前这个门,因为这样可以尽可能减少我们等待的时间,那我们直接贡献延后计算即可。
然后我们发现我们最多拿 \(\sqrt {lim}\) 把,钥匙,超过了不如直接冲,于是状态数变为 \(n \sqrt {lim}\),直接暴力即可。
5.节日游戏
这道题我们肯定得钦定一个顺序买才行,我们可以先去做 \(sub 5\),发现可以全买完的话,你一定可以找到一种最优方式去买,由于比较是有传递性,局部性的,那你直接邻项交换算一下贡献即可。
你取全部会最优,由于传递性,你取出一个子序列这个顺序依旧最优。
那你直接做就可以做到 \(O(n^2)\)。
现在来做一下 \(sub6\)。
性质为 \((A-p)t \lt A\)
发现有一个极其高妙的性质,由于怎么买都是亏的,若是购买商品 \(T>1\) 时,我们设当前买了 \(k\) 次,尝试归纳证明 \(k\) 的次数在 \(\log V\) 级别。
考虑当前是第一次购买有 \(w \leq A-1\),
第二次时,有 \(w \leq (A-1-p)t\),进一步 \(w \leq (A-p)t-t\),有 \(w \leq A-2\)
第 \(k\) 次时,有 \(w \leq(A-2^{k-2}-p) t\),进一步 \(w \leq A- 2^{k+1}\)。
如此证明最多选择 \(\log V\) 个物品。
后面的 \(t=1\) 时直接暴力选一个前缀。
考虑扩展到正解,发现一定有一个前缀是赚钱,后面全部都是亏钱,因为前面我们已经知道我们这是最优顺序了,所以有一定不存在先亏钱后赚钱,如果存在这样的,交换一下一定赚得更多。因此,我们只需要暴力的先选择一个前缀,后面直接做 \(sub6\) 做法即可,复杂度 \(O(n \log V)\)。
6.Developer
鬼题先鸽了....
7.两道料理
首先观察可得对于第一个序列的第 \(x\) 个数,一定要在第二个序列取到某个前缀之前取这个数,才可以得到贡献。
那我们不妨扫描第一个序列,动态维护第二个序列在第一个序列取完前 \(x\) 个时它完前 \(i\) 个数的最大贡献。
首先当地一个序列取完某个前缀之后,第二个序列的某些点如果还没取就无法得到权值了,第一个序列同理。但这还不够,我们需要钦定一个操作顺序,即当扫描到第 \(i\) 个位置时先是第一个序列往后拿一个值,之后再是第二个序列往后拿几个值。那我们的操作形如前后缀加,对于所有位置与前面位置的值 \(ckmin\)。我们可以用线段树维护每个位置的值,然后每次覆盖操作即为前面一个颜色段覆盖后面,我们可以知道颜色段总个数是均摊 \(O(n)\) 的,那我们直接暴力做,每次对一个区间覆盖即可,线段树可以维护,复杂度 \(O(n \log n)\)。
还有更加聪明一点的做法,每次维护差分,那你一个位置的答案就是前面的差分和,然后如果你插入的是一个正数差分,显然你一定会保留,否则你一直往后加差分直到变为正数再插进去,均摊也是 \(O(n)\),用 map 维护即可做到 \(O(n \log n)\)。
9.背包
同余最短路的比较板子的题目,直接做肯定做不了的,考虑题目给的这个奇怪的 \(10^{11} \leq V \leq 10^{12}\) 有什么用。
发现可以直接贪,取出性价比最高的物品当主元,其他的跑同余最短路算贡献,预处理出取到最优贡献时余数为 \(x\) 的最小的体积,以及对应的得到的贡献。
首先考虑直接取性价比高的错在哪,发现是余数可能拼凑出更优策略,我们可以跑同余最短路来达到效果。
但是这样干在查询的 \(V \leq MAXV^2\) 时是错的原因是,如果充分利用余数,那么一个余数会带来 \(V\) 的体积贡献,如果体积贡献太多的话,就会出现性价比最高的用负数个最优的情况,但这个题目 \(V \gt MAXNV^2\),所以直接这样干就是对的了。
10.Gellyfish and Mayflower
和上一个题目差不多。
对于满足上面要求的取出性价比最高的跑同余最短路,否则直接跑暴力,复杂度 \(n^2c\),需要注意的是,后续处理性价比最高有两种办法。
- 钦定一个点后,再记一维表示是否经过钦定点。
- 只对路径可以经过当前点的点钦定是否为性价比最高的。
11.滑雪 2
首先先做第一个 \(sub\),我们可以找出解的基本结构。
之后我们找性质,可以发现,对于一个权值,如果这个权值有一些人,我们最后至少保留一个,进一步,我们至少保留建造连接设施成本最小的一个,其他的可能会上升。
通过做 \(sub1\) 我们知道,我们只需要知道前面有多少个还没用过的设施,前面设施成本最小的是谁就可以,当前有多少个在移动就可以知道现在的代价。注意到通过我们找的性质前面设施成本最小的的人是不会动的,也就是说这一维是固定的不需要记,那就只要记到了权值为 \(i\) 的位置,有多少在移动,还有多少设施没用即可,朴素做是 \(O(n^3 V)\),找点性质优化再加上前缀和优化即可做到 \(O(n^2 V)\)。
注意到有用点只有 \(O(n)\) 个,直接把这些点取出来再跑就可以做到 \(O(n^3)\)。
12.救护车
首先设左上为 \(A\),右上为 \(B\),左下为 \(C\),右下为 \(D\)。
首先考虑只有一个左上角和右下角有点时怎么做,发现设 \(d1_x\) 表示点 \(x\) 到左上角的距离,\(d2_x\) 表示点 \(x\) 到右下角距离,不难发现 对于任意 \(x\),有\(d1_x + d2_x\) 为定值,把曼哈顿距离两轴平移到坐标轴上显然可以得到。那么贪心的考虑按 \(d1_x\) 排序,那么肯定一个前缀去左上角,一个后缀去右下角。
然后把对角线加入之后,发现就是一个前缀可以去 \(A,B,C\),后缀可以去 \(B,C,D\)。
再对于一个前缀按到 \(B\) 的距离排序,此时变成了,对于前缀排序后的一个前缀可以去 \(A,B\),后缀可以去 \(A,C\),那你直接设 \(A\) 容量为 \(x\) 时,另一个的最小容量是 \(y\),那你其实就是对于每个前缀做一个 \(O(n^2)\) 的背包合并。之后在对于整体枚举前缀做一个 \(O(n^2)\) 的背包合并,直接做复杂度就是 \(O(n^3)\) 的,可以通过。
至于这个是怎么想到的,我觉得是首先性质给了一个和相等取前后缀的提示,这时候其实就应该想到放宽条件找一个不变量再去贪心取前后缀,之后要想到可以用类似方法把另外两个点加入,感觉还是挺聪明的。
13.合唱
首先给出一个暴力做法,设 \(f_{i,j}\) 表示前 \(i\) 个位置,分了 \(j\) 组。前 \(min(s_A,s_B)\) 个已经匹配好了的方案,转移的时候注意到有一个式子形如 \(k x + b\),可以斜率优化一下。
之后不难证明交叉小于包含,有四边形不等式就可以 WQS 二分了。
14.Vim
首先可以先把 \(e\) 删掉,变为有一些位置必经。
朴素 DP 比较简单,就是设前 \(x\) 个已经搞完了,然后跳出的位置是后面第一个字符 \(c\),然后你每次再暴力往后跳进行转移就行了,复杂度是 \(O(n^2 \sum)\) 但是这个没什么前途。
我们考虑如何精准的刻画跳跃的过程。不难发现每个位置只会被经过 \(1\) 或 \(3\) 次,我们发现我们可以直接通过记下第一次跳跃终点的方式记下被经过一次的点,再通过记下第一次跳跃终点和第二次跳跃终点的方式刻画出来,但是我们肯定是不能直接把终点记下来的,因为终点个数是 \(O(n)\) 的,但是我们可以记下他下次跳跃跳到的是哪一个字符,等到到达跳到字符之后再更新即可,经过的点还是不变的,复杂度 \(O(n \sum ^2)\)。
转移是依托。
15.苹果树
题目可以转化为一条链可以免费拿走一个,其他的加起来可以选 \(k\) 个的最大权值。
发现这个东西只与这条链,链左侧点和链右侧点有关。更一步发现就是前序遍历一段拼上后序遍历一段再拼上这条链,朴素做要合并前序,链,后序三个背包,复杂度就三次方了。
我们考虑把前序和链的合并在遍历时直接放在一起处理,然后对于一个节点拼上他前面的儿子时,钦定儿子节点至少选一个,用来补上免费选的一个苹果,之后再后序遍历一遍。
这样就变成合并两个背包求单点了,可以 \(O(nk)\)。
16.火花
还不会。
17.百万富翁
首先有一个简单的分治做法,层数太多了。
考虑在层数比较小的情况下求出最小次数,那么现在一层如果有 \(n\) 个数,分成 \(x\) 组,现在是第 \(d\) 层。那么次数可以设个 dp,\(F(x) = \frac{x(x-1)}{2}\)。
\(f_{n,d} =\max_{m=2}^{m=n-1} (n \bmod m) \times (f_{\frac{n}{m}+1,d+1}+F(\frac{n}{m}+1)) + (m-n \bmod m) \times (f_{\frac{n}{m},d+1}+F(\frac{n}{m}))\),我们发现这个 \(m\) 大概率就是 \(n-1\) 的决策点往后的几个点,直接扫几个保留最优的就行了。
之后按照这个分组直接分就可以了。
18.A Independent Set
首先序列最后形态肯定形如 \(BBABBBABABAB\) 之类的东西。
当然可能结尾是个 \(A\), 为了方便处理我们先加个 \(B\) 在末尾。
我们考虑操作的区间一定是一些 \(cnt_A = cnt_B\) 的区间,然后把他们边成形如 \(ABABAB\) 的东西。然后之间是一些不动的 \(B\),感觉一下这个应该是对的,然后再考虑如果 \(cnt_A \gt cnt_B\) 这样就无法匹配的,否则肯定是可以调整成若干满足要求的区间再拼上中间一堆 \(B\) 的。
进一步,我们还有性质,如果当前位置为划分结尾,我们一定考虑的是最近的左端点满足 \(cnt_A=cnt_B\) 的。
这个应该是有点道理的,考虑如果一个满足 \(cnt_A=cnt_B\) 的段可以被划分成如果满足条件且不交的段,他们的移动是不会超出极小段,否则是不优的。
考虑一个段移动的贡献,如果我们按照上述只分配极小段,可以证明 \(A\) 的移动轨迹要么是全部向右走,要么是全部向左走。
考虑如果出现两个方向时,此时必然可以再划分出一个新段使得得到更小段,上面说明了是极小段,所以是正确的,复杂度 \(O(n)\)。

浙公网安备 33010602011771号