AT_agc033_d Complexity 题解
好题。
首先考虑最简单的区间 DP,
你会发现这个复杂度显然不太能接受。
我们考虑优化。不妨分析一下这个复杂度有什么性质。
直觉上来说,肯定是越大的矩形复杂度就越大。形式化的说,如果一个矩形的复杂度为
证明比较无脑,直接数学归纳法即可。
INFO 证明
首先对于
接下来我们考虑
接下来是
此时我们对第二个维度再应用归纳法。对于
考虑
- 对于所有
,上面的命题对于 大小的矩形成立。 - 对于所有
,上面的命题对于 大小的矩形成立。
我们分类讨论。在下方增加和在右侧增加是完全对称的,我们以在下方增加为例。
对于在下方增加一行的情况,考虑新矩形的最优分割。
- 横着切。此时有两种情况。
- 分割出来的其中一个小矩形就是原来的矩形本身。考察我们计算代价的函数
,这个权值肯定是大于 的。 - 否则,假设变成了一个大小为
和 的两个矩形。去掉最后一行,变成 和 的矩形。应用归纳假设,其中一个的权值变小不会更劣。
- 分割出来的其中一个小矩形就是原来的矩形本身。考察我们计算代价的函数
- 竖着切。此时去掉这一行两个矩形的高都变小了。应用归纳假设。两个权值都变小最终的
也不会更劣。
然后我们就证明了这个东西。
那么,我们接下来就有一个简单的做法可以将复杂度优化到四次方。
考虑固定
考察
可以证明,最优决策点一定会向右侧移动。在决策值相同的情况,选择最右侧的点。
INFO 证明
首先如果最优决策点仍然有
如果
另外一个证明方法是反证法。
INFO 证明
不妨假设最优决策点向左移动了。假设新的决策点为
考虑
那么,剩下的就是
而如果增大了,也就是
因而,我们可以做一个双指针,同时维护右端点和最优决策点,每次右移时,我们同时尝试向右侧移动最优决策点。
需要注意这里的后效性比较难处理。这个时候可以按照面积从小到大转移,每次转移完成之后在新的面积处添加一个转移当前矩形的任务。
这样的复杂度是
但是实际写一下就会发现这个东西会 TLE(我写的第一个点跑了 std::vector 常数太大了,并且我们稍后也有更加优秀的做法)。
对于这个做法对空间的处理,不难发现你如果每次对半砍,面积会减半,因此你最多切
因此我们可以使用一个经典的技巧,交换状态和答案。
令
此时的状态个数就是可以接受的了。
我们有两种转移。对于竖着切的情况,相当于在复杂度小于
第二种转移是横着切。
此时我们也有性质,
和我们一开始优化到四次方的做法一样,考虑固定
令
此时
双指针转移即可。复杂度
参考代码在这里。包含了四次方做法和