[HG]走夜路 题解

前言

整个机房就我一个人在想动态规划。
想了半天发现一堆性质,结果由于DP中出现折线挂了。

题目描述

某NOIP普及组原题加强版
\(Jim\) 非常怕黑,他有一个手电筒,设手电筒的电量上限为 \(T\)
\(Jim\) 回家的路上有 \((N + 1)\) 个充电站, \(0\) 是起点 \(N\) 是终点,
\(Jim\) 每走一个单位距离消耗一个单位的电量。
给出每个充电站到下一个充电站的距离 \(D\) ,以及冲单位电量的花费 \(P\) ,求整个旅途的最少花费。
P.S. 如果 \(Jim\) 无法保证全程 手电筒都亮着输出 \(-1\)

题解

有一个美妙的贪心。
对于当前 \(Jim\) 所在的点,
如果能走到 \(P\) 值比它小的充电站,就适量地充电并走到它,使走到第一个 \(P\) 值小于他的充电站时花费的钱最小;
如果走不到或找不到这样一个点就充满电,走到下一个充电站。
那么怎么找到第一个 \(P\) 值小于它的点呢,简单第使用二分加ST表即可。
时间复杂度为 \(\Theta(n\ logn)\)

代码

#include <cstdio>
#define int long long

int st[500005][26];
int lg2[500005];
int d[500005], p[500005];

#define min(a,b) ((a<b)?a:b)

void init(int n){
    lg2[1] = 0, lg2[2] = 1;
    for (int i = 3; i <= n; ++i)
        lg2[i] = lg2[i >> 1] + 1;
    for (int i = 1; i <= n; ++i)
        st[i][0] = p[i];
    for (int i = 1; i <= 25; ++i){
        int lim = n - (1 << i) + 1;
        for (int j = 1; j <= lim; ++j)
            st[j][i] = min(st[j][i - 1], st[j + (1 << i - 1)][i - 1]);
    }
}

inline int query(int l, int r){
    int i = lg2[r - l + 1];
    return min(st[l][i], st[r - (1 << i) + 1][i]);
}

#define max(a,b) ((a>b)?a:b)

signed main(){
    int n, t; scanf("%lld %lld", &n, &t);
    for (int i = 1; i <= n; ++i)
        scanf("%lld %lld", &d[i], &p[i - 1]), d[i] += d[i - 1];
    init(n);
    int pos = 0, eng = 0, cst = 0;
    while (pos < n){
        if (eng < 0){
            puts("-1");
            return 0;
        }
        int l = pos + 1, r = n, res = -1;
        while (l <= r){
            int mid = l + r >> 1;
            if (query(pos + 1, mid) <= p[pos]) r = mid - 1, res = mid;
            else l = mid + 1;
        }
        if (d[res] - d[pos] > t){
            cst += (t - eng) * p[pos];
            eng = t - (d[pos + 1] - d[pos]);
            pos++;
        }
        else{
            int tag = 0;
            if (eng > d[res] - d[pos]) tag = eng - d[res] + d[pos];
            cst += (d[res] - d[pos] - min(eng, d[res] - d[pos])) * p[pos];
            eng = tag; pos = res;
        }
    }
    printf("%lld", cst);
    return 0;
}
posted @ 2019-10-30 15:14  LinZhengmin  阅读(302)  评论(0编辑  收藏  举报

Contact with me