Dividing the Path

思路:
从左边往右边考虑,F[x]为区间[0,x]的解。因此所求为F[L]。
首先可以推断出,以下几点

  1. x 为偶数,因为洒水是以原点为中心画圆,所有直径不可能为奇数。
  2. 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;
}
























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值