題目鏈接:
http://codeforces.com/contest/635/problem/E
題意:
從座標爲0的地方出發到座標爲
分析:
之前在poj做過一個類貪心,是每個加油站油量有限,問最少需要經過多少加油站。
那一道貪心的原則是“直到走不到下一站,再在這個站加油。“
而這道題貪心原則就是“遇到便宜的就先把油加上,避免走到後面加更貴的油“,那麼我們怎麼保證遇到的是便宜的呢?可以預處理一遍,倒着推一遍,記錄每個加油站的後面的最近的比他便宜的,這樣到達該加油站只要加到能走到下一個便宜的就好了,然後到達下一個便宜的再加油。。。依次下去,如果某個加油站後面沒有比他更小的,那麼直接加滿,希望能用便宜的油多走一些路。
代碼:
#include<cstdio>
#include<stack>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define pr(x) cout << #x << ": " << x << " "
#define pl(x) cout << #x << ": " << x << endl;
#define sa(x) scanf("%d",&(x))
#define sal(x) scanf("%I64d",&(x))
#define xx first
#define yy second
#define mdzz cout<<"mdzz"<<endl;
const int maxn = 2e5 + 5, oo =0x3f3f3f3f;
typedef pair<int, int>p;
typedef long long ll;
int nt[maxn];
p s[maxn];
/*貪心 對於每個位置找最近的最小的,判斷距離,選擇充多少*/
int main (void)
{
int d, n, m;sa(d), sa(n), sa(m);
for(int i = 1; i <= m; i++){
int x, y;
scanf("%d%d", &x, &y);
s[i] = p(x, y);
}
s[0] = p(d, 0);
s[m + 1] = p(0, oo);
m += 2;
sort(s, s + m);
//倒着推一遍找下一個最小的
stack<int>q;
for(int i = m - 1; i >= 0; i--){
while(!q.empty() && s[i].yy <= s[q.top()].yy) q.pop();
if(q.empty()) nt[i] = -1;
else nt[i] = q.top();
q.push(i);
}
ll ans = 0;
int now = n;//還剩多少
int add = 0;//要加到多少
for(int i = 0; i < m; i++){
if(now < 0) return puts("-1"), 0;
if(nt[i] == -1){//最小的了,加到走到最後
add = d - s[i].xx;
}else add = s[nt[i]].xx - s[i].xx;
if(add > n) add = n;//最多n
if(add > now){
ans += (add - now) * 1ll * s[i].yy;
now = add;
}//選擇加油
now -= s[i + 1].xx - s[i].xx;
}
printf("%I64d\n", ans);
return 0;
}