愉快的推式子吧 (ノ≧∀≦)ノ!
设 fi 表示前 i 根柱子完工后的最小代价。枚举一个小于 i 的 j ,表示为从 j 向 i 连了一座桥,中间的柱子当然全部推掉,计算一下就好:
fi=minfj+(si−1−sj)+(hi−hj)2
*其中 s 为 w 的前缀和。
fi=fj+(si−1−sj)+(hi−hj)2fi=fj+si−1−sj+h2i+h2j−2hihjfj+si−1−sj+h2i+h2j=2hihj+fi
于是最终式子变成了 y=kx+b 的形式,斜率优化!
但是…… 注意这个式子的 k 不是单调递增的,并且 x 也不是单调递增的!那么我们不能用朴素做法了,也不能用二分…… 难道用 Splay ?(码量巨大) 。
不,用 CDQ 分治。
对于一个 i ,可能可以对 i 做出贡献的只有所有小于 i 的 j 。为了保证 x 单调我们先大力将原来的数组按照 x 从小到大排个序,然后 CDQ 的时候分左右两边,左边的所有元素在初始数组的位置都小于右边的左右元素,也就是说我们直接用左边元素对右边元素做出贡献。
同时这里也保证了左右两边的 x 一定是单调上增的。
我们使用单调队列,扫一遍左边的元素,留下能做贡献的点 (下凸壳上的点),这时候左边的所有元素可以保证 x 和斜率都是单调上增的。
右边呢?因为直线的斜率是 2x ,而右边的 x 也是单调上增的,所以我们可以愉快的做朴素的单调队列了。
CDQ 分治部分的代码:
最后因为存在 0 ,在计算斜率的时候需要特判一下。还需要注意一下 long long 的问题,记得将 f 数组初始化。
0 条评论