POJ2373-Dividing the Path【单调队列优化dp】

正题

题目链接:http://poj.org/problem?id=2373


题目大意

长度为L,要求每个区域都被洒水器覆盖,而且在每只奶牛的喜爱区域只能由一个洒水器覆盖,洒水器必须放在整数点,喷洒半径只能在 a ∼ b a\sim b ab区间。


解题思路

我们考虑dp,我可以先想 O ( n 2 ) O(n^2) O(n2)的。

f i = m i n { f j } + 1     ( i − 2 b ≤ j ≤ i − 2 a ) f_i=min\{f_j\}+1\ \ \ (i-2b≤j≤i-2a) fi=min{fj}+1   (i2bji2a)

然后我们可以用单调队列维护一下区间。
然后我思考奶牛的问题,奶牛所在的区间不可以有洒水器的中断,而 f i f_i fi表示的是最后一个洒水器在 i i i位置中断需要的最少洒水器数量,所以我们保证在奶牛喜爱的区域再往内一圈 f i f_i fi的值都为 i n f inf inf就好了。


code

#include
#include
#include
#include
#define inf 0x3f3f3f3f
using namespace std;
deque<int> q;
int n,l,a,b,w[1000010],f[1000010],x,y,sum;
int main()
{
	scanf("%d%d%d%d",&n,&l,&a,&b);
	b=2*b;a=2*a;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		w[x+1]++;w[y]--;//标记
	}
	for(int i=2;i<=l;i+=2){
		sum+=w[i]+w[i-1];//记录前缀和
		while(!q.empty()&&i-b>q.front())
		  q.pop_front();//维护区域
		int addn=i-a;//维护区域
		if(addn>=0)
		{
		  while(!q.empty()&&f[q.back()]>=f[addn])
		    q.pop_back();//维护单调性
		  q.push_back(addn);//加入队列
		}
		if(!q.empty()&&f[q.front()]<inf&&!sum) 
		  f[i]=f[q.front()]+1;//有值
		else f[i]=inf;//无值
	}
	printf("%d",f[l]==inf?-1:f[l]);//输出
}

你可能感兴趣的:(dp,数据结构)