Description
(Jim)是一个胆小的男生,可是每天他都要学习到很晚才能回家,而且他回家的路上没有路灯。
(Jim)非常怕黑,万幸的是他还有一个手电筒可以用,我们设手电筒的电量上限为(T)。
在(Jim)回家的路上有((N+1))个充电站,(0)是起点(N)是终点,(Jim)每走一个单位距离消耗(1)个单位的电量。
给出每个充电站到下一个充电站的距离(D),以及充单位电量的花费(P),求整个旅途的最少花费。
如果(Jim)无法保证全程手电筒都亮着输出(-1)。
Input
第(1)行: (2)个数(N),(T)中间用空格分隔,(N+1)为充电站的数量,(T)为手电筒的电池容量((2≤N≤500000,1≤T≤10^9))。
第(2)至(N+1)行:每行(2)个数(D[i]),(P[i]),中间用空格分隔,分别表示到下一个充电站的距离和充电的单价((1≤D[i], P[i]≤1000000))。
Output
输出走完整个旅程的最小花费,如果无法保证手电筒全程照亮,输出(-1)
Sample Input
3 15
10 2
9 1
8 3
Sample Output
41
Data Constraint
对于(30)%的数据(N<=50)
对于(100)%的数据(N<=500000)
Limit
(1000ms) (256MB)
Solution
贪心,贪心思路是如果在电量T范围,能够到下一个比当前充电便宜的地方(next),就充到刚好到下一个地方的所需的电。
否则就充满电,到下一个点继续判断。
对于每个点的next,可以O(n)的单调栈预处理。
Code
#include<iostream>
#include<cstdio>
#define ll long long
#define N 500007
using namespace std;
ll ans, n, t, w, rest, now;
ll d[N], p[N], pre[N], nxt[N], q[N];
inline ll read() {
ll s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 3) + (s << 1) + (c ^ 48);
return (s * w);
}
int main() {
freopen("wayhome.in","r",stdin);
freopen("wayhome.out","w",stdout);
n = read(), t = read();
for (register int i = 1; i <= n; i++) {
d[i] = read(), p[i] = read();
pre[i] = pre[i - 1] + d[i];
if (d[i] > t) {
printf("-1
"); return 0;
}
}
for (register int i = n; i; i--) {
while (w && p[q[w]] > p[i]) w--;
nxt[i] = q[w];
q[++w] = i;
if (!nxt[i]) nxt[i] = n + 1;
}
for (register int i = 1; i <= n; i++) {
rest = rest - d[i - 1];
now = min(pre[nxt[i] - 1] - pre[i - 1], t);
if (now > rest) ans = ans + (now - rest) * p[i], rest = now;
}
printf("%lld", ans);
return 0;
}