[10.3模拟赛]T2

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;
}
只要有想见的人,就不是孤身一人了。
原文地址:https://www.cnblogs.com/Agakiss/p/11789298.html