[贪心] 51Nod1288 汽油补给

来源:互联网 发布:redis结合mysql 编辑:程序博客网 时间:2024/04/28 16:55

经典题吧…考虑最近的一个比当前位置便宜的位置 nxt,若能到达,就原地加油至刚好能到 nxt,然后过去。
若加满油都到不了 nxt,就先原地加满油,在能到达的位置中选最便宜的去。
数据结构优化一下就好啦。

#include<cstdio>#include<cmath>#include<algorithm>using namespace std;typedef long long LL;const int maxn=100005;int n,m,p[maxn],nxt[maxn],_max[maxn],stk[maxn],top,st[maxn][20];LL ans,d[maxn];void make_st(){    for(int i=1;i<=n;i++) st[i][0]=i;    for(int j=1;(1<<j)<=n;j++)     for(int i=1;i+(1<<j)-1<=n;i++)      st[i][j]=p[st[i][j-1]]<=p[st[i+(1<<j-1)][j-1]]?st[i][j-1]:st[i+(1<<j-1)][j-1];}int Query(int L,int R){    int t=log2(R-L+1);    return p[st[L][t]]<=p[st[R-(1<<t)+1][t]]?st[L][t]:st[R-(1<<t)+1][t];}int main(){    freopen("51nod1288.in","r",stdin);    freopen("51nod1288.out","w",stdout);    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) scanf("%d%d",&d[i],&p[i-1]), d[i]+=d[i-1];    for(int i=0;i<=n;i++) nxt[i]=n;    for(int i=n;i>=0;i--){        while(top&&p[i]<=p[stk[top]]) top--;        nxt[i]=stk[top]; stk[++top]=i;    }    for(int i=0,p=0;i<=n-1;i++){        p=min(p,i); while(p<n&&d[p+1]-d[i]<=m) p++; _max[i]=p;         if(_max[i]==i) return printf("-1"),0;    }    make_st();    int i=0; LL v=0;    while(i<n){        if(d[nxt[i]]-d[i]<=m){            LL tmp=max(0LL,d[nxt[i]]-d[i]-v);            ans+=tmp*p[i];            v+=tmp-(d[nxt[i]]-d[i]); i=nxt[i]; continue;         }        int t=Query(i+1,_max[i]);        ans+=(LL)p[i]*(m-v); v=m-(d[t]-d[i]);        i=t;    }    printf("%lld\n",ans);    return 0;   }