hdu 5380 Travel with candy 贪心&队列

本文介绍了一种算法,用于解决在给定路径上以最低成本购买物品的问题。具体地,问题设定为一个人从起点到终点行走,途中需要购买物品,目标是最小化总花费。文章详细解释了使用双端队列来优化购买和售卖策略的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:A想从0走到n,A每走一单位的距离就要吃一颗糖,现在给出第i个点离0的距离a[i](保证a[i] < a[i+1]),和每个点买入一颗糖和卖出一颗糖的单价buy[i]和sell[i],A能携带糖的上限为C,问从0走到n的最小花费。

如何使得花费最小?低价买入&高价卖出这种情况可以使得花费最小,而且走的顺序是定下来的。。必须从0…1…2…3…n,可以这么做,记录走到每个点都满载的情况花费,然后只需要考虑退油该怎么退,退油的时候减去卖价高的,走到每一个点,对于买入价格小于当前卖价的那些油,都合并成当前卖价买入,对于买入价格大于当前买价的那些油,都以原价退回,这里的“原价”不是一定是原价,而是可以为卖出的价格,将退油的时机改为原价买原价卖改为原价买高价卖。
这些操作需要一个双端队列。。
贴标程。。。。
代码:

//author: CHC
//First Edit Time:  2015-08-17 13:34
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=200000+1000;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
struct que {
    int val,cnt;
}Q[MAXN*2];
int l,r,tot;
LL ans;
void Max(int v){
    int num=0;
    while(l<=r&&Q[l].val<v){
        num+=Q[l].cnt;
        l++;
    }
    if(num){
        --l;
        Q[l].cnt=num;
        Q[l].val=v;
    }
}
void Min(int v){
    while(l<=r&&Q[r].val>v){
        ans-=1LL*Q[r].val*Q[r].cnt;
        tot+=Q[r].cnt;
        --r;
    }
}
void Del(int v){
    while(v){
        int t=min(Q[l].cnt,v);
        Q[l].cnt-=t;
        v-=t;
        if(Q[l].cnt==0)++l;
    }
}
int A[MAXN],n,c,sell[MAXN],buy[MAXN];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&c);
        A[0]=0;
        for(int i=1;i<=n;i++)scanf("%d",&A[i]);
        for(int i=0;i<=n;i++)scanf("%d%d",&buy[i],&sell[i]);
        l=r=n;
        --r;
        ans=0;
        for(int i=0;i<n;i++){
            //将买入价小于卖出价的合并
            Max(sell[i]);
            //补充使得满油
            tot=(i==0)?c:A[i]-A[i-1];
            //将买入价大于当前买入价的油都退了,更新答案并计算需要补充的油tot
            Min(buy[i]);
            //将买入的油数量和单价入队列
            Q[++r].val=buy[i];
            Q[r].cnt=tot;
            ans+=1LL*buy[i]*tot;
            //消化从i...i+1这个点的油(最便宜的
            Del(A[i+1]-A[i]);
        }
        //更新最后一个点
        Max(sell[n]);
        //把多余的油退掉
        for(int i=l;i<=r;i++)ans-=1LL*Q[i].val*Q[i].cnt;
        printf("%I64d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值