雪莉杂俎
雪莉杂俎
1. 杂谈
1.1 猜结论
只要考场上发现一个问题十分难解决,可以破除该限制,来解决问题,然后试图证明在有限制的情况下这个方案仍然正确。
例题:[G2029 届训练 11:模拟赛] T1 插入统计水桶
这道题看到一个和0取max的操作非常的烦人,我们可以尝试不要它,并且可以将 \(v\) 和 \(l\) 给拆开,尝试让尽可能多的前若干大的 \(v\) 和前若干小的 \(l\) 来匹配,直接贪心即可。至于该如何证明,笔者其实并不会。
1.2 凸包
如果问题的答案由若干一次函数相加得到,如果要求求最值,那么答案是一个凸包。
例题:[G2029 届训练 23:定时练习] T2 Minimum Spanning Tree
这道题每条边的边权都是一次函数,那么最小生成树的大小也必然是一次函数,本题要求 \(x\) 属于一段区间的最小生成树中的最小值,那么答案关于 \(x\) 肯定会形成上凸包,直接取 \(l\) 和 \(r\) 的值即可。
1.3 博弈论
在博弈的过程中可以试图发现有什么东西是不变量,导致最终的胜负。
例题:Nim游戏
Nim游戏肯定是人尽皆知的,我们可以用打表的方式得出先手必胜和后手必胜的状态,然后可以从小数据看起,发现只要各堆石子数异或和为零先手必输(可以看出来吗?),然后直接做就可以了。
1.4 Baka's Trick
在维护一些需要滑动窗口的问题时,如果删除操作难以进行,但是容易维护撤销操作,那么可以维护一个对顶栈,当左边的栈为空时,可以将右边的栈的元素全部重构到左边,最后求答案只需要合并两侧答案。
例题:[G2029 届训练 36:DP 转移优化(一)] T3 Knapsack and Queries
这道题首先观察数据范围,发现有个加入的重量是逐渐变大的性质,而删除物品是删除最小的,于是这就是一个滑动窗口,而最值的背包问题撤销是非常难以执行的,就可以应用 Baka‘s trick.
1.5 最值问题的0-1化处理
对于某些与第 \(k\) 大相关的问题,我们可以枚举或二分 \(x\) 为答案,将大于等于它的值变为 \(1\) ,小于的变为 \(0\),再进一步处理。
例题1:[G2028级训练251(NOIP2026水平能力测试 Round12)] 第二个宝石装置
对于求解这个区间的子区间第 \(c\) 大之和的问题,我们可以从高到低逐渐加数,并且使用 std::set 来维护新增的相邻的长度为 \(c\) 的 \(1\) 子序列,加入为一个矩形,使用历史区间和线段树维护即可。
例题2:[G2028级训练244(NOIP2026水平能力测试 Round8)] T3 逐层评审
这道题可以先二分一个最后答案,然后0-1化处理,剩下只需要处理01串的增长就可以了,读者不难自行解决,笔者不进行解释。
2.决策单调性
2.1 决策单调性的判断
已知转移式:
如果能够证明对于任意 \(W(a,i)-W(b,i)\) 随着 \(i\) 单调变化,那么就具有决策单调性。如果对于最小值的话只要证明 \(W(a,i)-W(b,i)\) 是单调不降的,那么最优决策点会向右移动,反之,对于最大值,如果证明 \(W(a,i)-W(b,i)\) 单调不升,那么最优决策点也会向右平移。应用此结论,我们也可以推导出四边形不等式,也就是如果我们证明了 \(\forall a \leq b < c \leq d,W(a,d)+W(b,c) \leq W(a,c)+W(b,d)\) 可以得到最小值的结论,反之就是最大值。
2.2 决策单调性的栈的处理
当目前为 \(i\) 时,可以对于每个决策点 \(j\) 维护一个三元组 \((j,l,r)\) 表示转移到这些位置最优,然后遇到新决策点的时候,从栈顶开始,如果在 \(l\) 位置 \(j\) 都不如 \(i\) 优,那么就弹掉栈顶,如果 \(i\) 刚好卡到中间,那么可以二分断点。
例题:[G2029 届训练 36:DP 转移优化(一)] T1 诗人小G
这道题可以得出 \(W(j,i)=|pre[i] + i - (pre[j] + j) - 1 - L|^P\) ,这个函数不难证明四边形不等式,那么我们就可以应用栈处理,就可以快速解决了,详细过程参考上文。
2.3 决策单调性分治处理
对于状态有两维的,例如:
可以进行分治,令当前可用决策点为 \([L,R]\) 待转移的点为 \([l, r]\) 可以暴力求出 \(mid\) 的最优决策点 \(opt\)
,然后再递归到 \(\{[L,opt],[l, mid - 1]\}\) 和 \(\{[opt, R],[mid + 1, r]\}\) 进一步转移。
例题:[G2029 届训练 36:DP 转移优化(一)] T5 Partition Game
这道题虽说有线段树的做法,但是其实也是可以决策单调性的,写出转移后直接应用即可。
2.4 反向决策单调性的Baka's Trick模拟单调队列处理
如果对于任意 \(W(a,i)-W(b,i)\) 随着 \(i\) 单调变化的方式与 2.1 中提到的方式相反,那么决策点会向左移动,但通常情况下,我们选取的 \([j+ 1,i]\) 区间会受到限制,可能会使最小合法转移点向右滑动,导致原先的决策点不合法。如果没有删除的操作,那么可以直接维护单调栈,移除的决策点一定不优。但增添了删除操作,我们难以知晓一些被移除的决策点回来后是什么情况,就可以应用 Baka's Trick,就可以比较好的维护删去元素后回来的元素是什么,因为单调栈是可以撤销的,能够知道回来的元素是什么。
例题 [G2029 届训练 37:DP 转移优化(二)] T5 Bookshelf G
这个神题要求了区间宽度之和不能超过 \(L\),并且区间的最大值明显是满足反向四边形不等式的(不用解释吧?),那么就可以应用反向决策单调性的处理了。
3. 随机化
3.1 随机序列下前缀最大值个数为 \(O(\log n)\)
对于某些答案需要在不同决策点决定最值的问题,并且存在一种较快方式判断当前答案是否在该决策点更优秀的方式,可以将决策点随机打乱,每次取最大值,就可以将时间复杂度降低到 \(O(\log n)\).
例题:[G2028级训练251(NOIP2026水平能力测试 Round12)] T2 宝石装置
这个题暴力的 \(O(n^2\log n\log V)\) 做法就是外层枚举起点,然后二分答案。而我们获得一个答案,是可以使用二分中的 check 函数来快速判定,而不同的起点就是不同的决策点,于是时间复杂度变为 \(O(n\log^2 n\log V)\)
4. 志怪
4.1 线性RMQ
考虑将序列分为长度为 \(64\) 的小块,块之间可以使用经典 st表,这部分时间复杂度为 \(O(\frac{n}{64}\log \frac{n}{64})\) 的,其实也就是 \(O(n)\) 的,然后块内使用 long long 类型存储那些值是后缀的前缀最大值,使用单调栈就可以实现,整块使用 st表,散块的话,就可以直接在单调栈上查询,总时间复杂度就是线性的,本质上是使用位运算来节省部分时间。
4.2 超级内存优化矩阵乘法
可以在枚举的时候将 \(k\) 放在中间,因为这样可以使内存更加连续,并且可以将 \(a[i][k]\) 给提前存一下。更进一步地优化,可以将矩阵的行和列都按照 \(32\) 分为很多块,每一块内部做矩阵乘法,最后再一起做矩阵乘法,\(2000\) 的矩阵乘法可以只跑 8s,但其实没有必要。

浙公网安备 33010602011771号