单调队列优化dp-----nkoj3662划区灌溉

划区灌溉

Time Limit:10000MS  Memory Limit:65536K
Total Submit:16 Accepted:10 
Case Time Limit:1000MS

Description

约翰的奶牛们发现山脊上的草特别美味.为了维持草的生长,约翰打算安装若干喷灌器.为简化问题,山脊可以看成一维的数轴,长为L(1≤L≤10^6),而且L-定是一个偶数.每个喷灌器可以双向喷灌,并有确定的射程,该射程不短于A,不长于B,A,B(1≤A≤B≤10^3)都是给出的正整数.它所在位置的两边射程内,都属它的灌溉区域.注意,一个喷灌器往左右两边喷射的距离是一样的,比如往左喷的距离是x,那么往右也是x,(A<=x<=B)。 
现要求山脊的每一个区域都被灌溉到,喷灌器不能将水喷到山脊以外的区域,而且喷灌器的灌溉区域不允许重叠, 约翰有N(1≤N≤10^3)只奶牛,每一只都有特别喜爱的草区,第i奶牛喜爱的草区是[Si,Ei],不同奶牛的草区可以重叠(Ei-Si<=2*B).现要求,每只奶牛的草区仅被一个喷灌器灌溉. 寻找最少需要的喷灌器数目.

Input

第一行,两个整数N和L 
第二行,两个整数A和B 
接下来N行,每行两个整数S和E(0 <= S < E <= L),表示每头奶牛喜欢的草区的起止位置 

Output

一行,一个整数,表示最少需要的喷灌器的数量,若无解,输出-1

Sample Input

样例输入1:
2 8
1 2
6 7
3 6

样例输入2:
4 202
10 12
21 27
32 39
103 121
163 180

Sample Output

样例输出1:
3

样例输出2:
10

Hint

样例1说明: 
 

Source

usaco 2004 dec gold


<pre name="code" class="cpp">#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<deque>
#define inf 1e9
using namespace std;
struct node{
	int l,r;//记录每头牛喜欢草地的左界和右界 (或者队列里的元素) 
	node(){}
	node(int a,int b){l=a;r=b;}
};
bool ok[1000005];//ok记录每一个草区是否是奶牛所喜欢的 
int f[1000005];//f[i]表示从0--i号草区所需的最少喷灌器 
node cow[10005];
bool flag=true;//记录是否无解 
deque<node>q;
int main(){
	int n,l,a,b,i,j,k,temp; 
	scanf("%d%d%d%d",&n,&l,&a,&b);
	for(i=1;i<=n;i++){
		scanf("%d%d",&cow[i].l,&cow[i].r);//init 
		if(cow[i].r-cow[i].l>2*b){
			flag=false;
		}
	}
	ok[0]=true;
	if(flag){
		for(i=1;i<=l;i++){
			f[i]=inf;ok[i]=true;
		}
		for(i=1;i<=n;i++){
			for(j=cow[i].l+1;j<cow[i].r;j++){//取用开区间 
				ok[j]=false;
			}}
		q.push_back(node(0,0));
		for(i=2*a;i<=l;i+=2){
			temp=i-2*a;//第i号草区当然应该讨论i-2*a到i-2*b 
			if(ok[temp]){
				while(q.size()&&q.back().r>=f[temp])q.pop_back();
				q.push_back(node(temp,f[temp]));
			}
			temp=i-2*b;
			while(q.size()&&q.front().l<temp)q.pop_front();
			if(ok[i]&&q.size())f[i]=q.front().r+1;//只有在第i号草区不属于每一头牛的喜欢区域才可以dp,否则搞成inf 
		}
	}
	if(flag==false||f[l]>=inf)cout<<"-1";
	else cout<<f[l];
}



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值