单调队列优化的 dp。首先我们先进行预处理,将可以合并的区间合并到一起,这个可以在 O(nlgn) 的时间内完成。方法是按照 x 排序,然后找相邻的两个区间 (a,b) 和 (c,d) 是否满足 a<d 并且 b>c,注意这里必须严格大于才行,因为这里的区间都是开区间,如果存在 b=c 这样的情况,那么 b 这个点就可以分割。
然后进行动态规划转移,令 dp[i] 为前 i 个区间可以划分的最小区间数目,那么就有:
dp[i]=min{dp[i−2k]}+1, A≤k≤B
如果不存在这样的 k 值,或者 i 是在某个区间内,那么 dp[i] 就为 ∞,注意初始化 dp[0]=1,dp[1]=∞。
运用类似多重背包的方法将 i 划分成 2 的一个剩余类,也就是说我们可以对上式进行变形,变成如下的形式:
dp[mod+2j]=min{dp[mod+2k]}+1,A≤j−k≤B
这里 dp[mod+2j] 是个仅关于 j 的函数,可以用单调队列维护一定区间的最值,最后问题得到解决。
注意这题的一些细节,首先当 L 为奇数的时候 dp[L] 与 dp[1] 属于同一个剩余类,那么 dp[L] 就为 ∞,所以直接可以输出 −1。其次,对于判断 i 是否在区间内,可以用一个指针 p 动态向后移动的方式来判断,如果第 p 个区间的右边界小等于 i,那么 p 就右移,知道 p 等于 n 或者右边界大于 i 为止,这时候判断第 p 个区间的左边界是否比 i 小,如果左边界小于 i,那么 dp[i] 就是 ∞。最后,如果 dp[L] 等于 ∞ 记得输出 −1。
这里还有一个很好的技巧,在队列中加一个哨兵 ∞,它的 id 也为 ∞,这样可以处理如果 i<A 的情况,当然也可以直接预处理出对所有的 i<A 都有 dp[i]=∞,注意这里枚举和 0 的同剩余类的元素要从 2 开始循环!