POJ2373动态规划

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

 

我的代码:

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值