CF1787H 题解
搞了很久才搞明白,写一篇比较详细的题解造福一下后人(
Sol
首先不妨转化一下,把最大得分转化成最小扣分,于是我们发现如果要做题,就要优先做 大的,因为他分减的最快。也可以选择不做他,得分取到 ,那么把它放在最后做肯定不劣。
于是我们把这些题按照 排序,记 ,设 表示前 道题,有 道不取 的扣分最小值,容易得到转移:
这是 的 DP,我们尝试发现一些东西来优化它。。
如果你真的写出这个 DP 打表并期望得到一些规律:
for(int i=1;i<=n;i++){
f[i][0]=f[i-1][0]+p[i].c;
for(int j=1;j<=i;j++)
f[i][j]=min(f[i-1][j]+p[i].c,f[i-1][j-1]+p[i].k*j);
}
如果你跑一下最后一组样例并把 输出:
5
10 15
29 20 19
44 35 34 15
52 43 42 23 8
56 47 46 27 12 4
62 53 52 33 18 10 6
80 68 62 51 36 28 24 18
81 69 63 52 37 29 25 19 1
105 85 75 71 62 49 43 41 29 21
你会惊喜地发现 关于 是下凸的。
既然发现了它的凸性,我们不妨差分吧!设 ,我们用 替换 即可得到:
把不变的东西提出来:
我们知道 ,所以:
为了把单个的 拎出来,我们将上式中的 替换为 :
然后将两式相减:
最后你发现这不还是 的吗。。不过如果你真的把这个 DP 写出来并且打表,然后跑最后一组样例并输出 :
0
-22 5
-22 -9 10
-22 -9 0 15
-22 -9 0 4 18
-22 -9 0 4 11 21
-22 -9 0 4 9 14 24
-22 -12 -6 3 7 12 17 27
-22 -12 -6 3 7 12 17 23 30
-26 -20 -10 -4 5 9 14 19 25 32
你会发现,每一行的前面一段相对于上一行不变。如果你注意力极其惊人,你会发现每一行的后面一段对于上一行的后面一段的差是个定值!!1
结合一下,我们的转移里面有 函数,说明其中有规律可言, 函数到底取哪个值是有规律的。
打表发现, 固定,存在一个最小的 满足 ,使得对于所有的 ,,其余的 都不满足这个。
而 就相当于 往后移一位,所以我们可以分成三段来讨论:
- 两个 全取前面那一项,对应 ,。
- 第一个 取后面一项,第二个取前面一项,在 处插入 。
- 两个 全取后面那一项,对应 ,。
如果你把这些全部注意到了,那么恭喜你,直接平衡树维护上述过程就可以过掉了。
但是你还不满足,为什么是这样的呢???
这基于一个关键条件:对于任意的 ,有 。
我们考虑归纳证明这个条件,对于 显然成立就不展开了。
当我们对于一个 ,将其转移到 时,考虑上述转移的过程:
先找到一个最小的 满足 。
对于左边不变和右边同时增加的那一部分,我们知道 是不增的,所以肯定满足。
对于 和 之间,有:。
我们知道 不满足 ,也就是说 。
所以有 。即满足。
对于 和 之间,有:。
优雅结束。
回顾一下本题的历程,我们首先取原 DP 数组的差分,然后注意到差分的差分大于一个数由此得出单调性,或许在场上对于我这种,除了打表没什么其他方法吧!
这就是你和 CF 3300 的差距。 —— 一休哥777
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】