【51Nod1288】汽油补给

有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2…… -> N,车每走1个单位距离消耗1个单位的汽油,油箱的容量是T。给出每个城市到下一个城市的距离D,以及当地的油价P,求走完整个旅途最少的花费。如果无法从起点到达终点输出-1。
例如D = {10, 9, 8}, P = {2, 1, 3},T = 15,最小花费为41,在0加上10个单位的汽油,在1加满15个单位的汽油,在2加2个单位的汽油,走到终点时恰好用完所有汽油,花费为10 * 2 + 15 * 1 + 2 * 3 = 41。
Input
第1行:2个数N, T中间用空格分隔,N + 1为城市的数量,T为油箱的容量(2 <= N <= 100000, 1 <= T <= 10^9)。
第2至N + 1行:每行2个数D[i], P[i],中间用空格分隔,分别表示到下一个城市的距离和当地的油价(1 <= D[i], P[i] <= 1000000)。
Output
输出走完整个旅程的最小花费,如果无法从起点到达终点输出-1。
Input示例
3 15
10 2
9 1
8 3
Output示例
41

题解
如果一个点能到向下一个花费小的点,则加需要的油往那个点走,否则加满油往下一点点走。

代码

#include<bits/stdc++.h>
#define mod 19260817
#define inf 1000000005
#define pa pair<int,int>
typedef long long ll;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,T,d[100005],p[100005];
ll sum[100005],ans;
int r,q[100005],point[100005];
int main()
{
    n=read();T=read();
    for (int i=1;i<=n;i++)
    {
        d[i]=read();p[i]=read();
        sum[i]=sum[i-1]+d[i];
        while (p[q[r]]>=p[i]&&r)
        {
            point[q[r]]=i;
            r--;
        }
        q[++r]=i;
    }
    int i=1,t=0;
    while (i<=n)
    {
        if (t<0){printf("-1");return 0;}
        if (point[i]==0)
        {
            if (sum[n]-sum[i-1]<=T)
            {
                ans+=(ll)max(sum[n]-sum[i-1]-t,0LL)*p[i];
                break;
            }
            else
            {
                ans+=(ll)(T-t)*p[i];
                t=T-d[i];
                i=i+1;
            }
        }
        else
        {
            if (sum[point[i]-1]-sum[i-1]<=T)
            {
                ans+=(ll)max(sum[point[i]-1]-sum[i-1]-t,0LL)*p[i];
                t=max(sum[point[i]-1]-sum[i-1],1LL*t)-sum[point[i]-1]+sum[i-1];
                i=point[i];
            }
            else
            {
                ans+=(ll)(T-t)*p[i];
                t=T-d[i];
                i=i+1;
            }
        }
    }
    if (t<0){printf("-1");return 0;}
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值