划区灌溉
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];
}