思路:
从左边往右边考虑,F[x]为区间[0,x]的解。因此所求为F[L]。
首先可以推断出,以下几点
- x 为偶数,因为洒水是以原点为中心画圆,所有直径不可能为奇数。
- F[x] = F[y]min + 1, y = [x-2B, x-2A]。 因为半径为A——B,所有只有x-2B 到 x-2A 之间才能通过再加一个点达到x。
那么如何快速求得[x-2B, x-2A]中的y,使得F[y]最小?需要使用优先队列,在每次完成一个点的计算之后,增加计算下一个点所需的信息到优先队列中。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
#include <limits.h>
#include <iomanip>
#include <queue>
#include <cstring>
using namespace std;
typedef long long LL;
typedef vector<int> vec;
//#pragma GCC optimize(2)
const static int INFINITE = 1<<30;
static int N, L, A, B;
static vector<int> Is(1000010);
static vector<int> F(1000010);
struct node{
node(int _x, int _fx): x(_x), fx(_fx) {}
int x;
int fx;
bool operator<(const node& a) const{
return fx > a.fx;
}
};
static priority_queue<node> q;
int main()
{
freopen("E:\\Desktop\\data.txt", "r", stdin);
//ios::sync_with_stdio(false);
cin >> N >> L >> A >> B;
A <<= 1;
B <<= 1;
for (int i = 0; i < N; i++) { //使用查分,快速求得那些点有奶牛
int s, t;
cin >> s >> t;
Is[s+1]++;
Is[t]--;
}
int cc = 0;
for (int i = 0; i <= L; i++) {
F[i] = INFINITE;
cc += Is[i];
Is[i] = cc > 0;
}
for (int i = A; i <= B; i+=2) { //初始化优先队列
if(! Is[i]){
F[i] = 1;
if(i <= B+2-A)
q.push(node(i, 1));
}
}
for (int i = B+2; i <= L; i+=2) {
if(! Is[i]){ //使用优选队列,根据F[x] = F[y]min + 1 求F[x]
node cc(0, 0);
while (! q.empty()) {
cc = q.top();
if(cc.x < i - B)
q.pop();
else
break;
}
if(! q.empty())
F[i] = cc.fx + 1;
}
if(F[i+2-A] != INFINITE) // 为求F[x+1]做准备
q.push(node(i+2-A, F[i+2-A]));
}
if(F[L] == INFINITE)
cout << -1 << endl;
else {
cout << F[L] << endl;
}
return 0;
}