思路:
从左边往右边考虑,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; }
```