HDU5380 Travel with candy

思路:     

1、保持油箱的油一直是满的。

2、到达每个城市之后,先将到达这个城市的花费减掉,这些消耗掉的应该是价格最低的。

3、对于油箱中的油的价格如果比当前城市买入的价格更高的话就直接退出油箱(退出油箱的意思:直接以购买的价格卖出 (这里的购买价格是会改变的) ),对于油箱中的油如果价格比当前城市卖出的价格低的话,那么可以将这些油的价格改成当前城市卖出的价格(可以想象成在当前城市卖出这些油,然后以卖出的价格买回来这部分油)。

4、然后在这个城市买油加满油箱。

这些操作可以用一个双端队列来维护。


#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <queue>
#define mp make_pair
#define INF 1000000000
#define MAXN 200050
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define P pair<int,int>
#define LL long long
using namespace std;

int a[MAXN];
LL buy[MAXN],sell[MAXN];
int len[MAXN];
LL now[MAXN];
int q[MAXN];
void work(){
    int st=0,ed=0;
    int n,c;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    for(int i=0;i<=n;++i)scanf("%I64d%I64d",&buy[i],&sell[i]);

    now[0]=c;
    q[ed++]=0;
    LL ans=c*buy[0];
    for(int i=1;i<=n;++i){

    	//扣掉到达这个城市的消耗
        int dis=a[i]-a[i-1];
        LL sum=c-dis;
        while(dis){
            int x=q[st];
            if(now[x]>dis){
                now[x]-=dis;
                dis=0;
            }else{
                dis-=now[x];
                now[x]=0;
                st++;
            }
        }

        //如果油箱中的油的价格小于当前城市的卖出价格,那么这些油的价格会等于当前城市的卖出价格,可以想象成在这个城市全部卖出,然后再原价买回来。
        int era=0;
        while(st<ed){
            int x=q[st];
            if(buy[x]<sell[i]){
                era+=now[x];
                st++;
            }else
                break;
        }
        if(era!=0){
            st--;
            now[q[st]]=era;
            buy[q[st]]=sell[i];
        }


        //对于油箱中价格比当前城市买入价格更高的油,全部直接退出油箱。以原来的价格卖掉。
        bool flag=true;
        while(flag&&st<ed){
            flag=false;
            int x=q[ed-1];
            if(buy[x]>=buy[i]){
                flag=true;
                ans-=now[x]*buy[x];
                sum-=now[x];
                now[x]=0;
                ed--;
            }
        }

        //将油箱加满。
        q[ed++]=i;
        now[i]=c-sum;
        ans+=(c-sum)*buy[i];
    }

    //将邮箱中剩余的退出。
    while(st<ed){
        int x=q[st++];
           ans-=now[x]*buy[x];
    }
    printf("%I64d\n",ans);
}
int main()
{
    len[0]=len[1]=0;
    for(int i=2;i<MAXN;++i){
        int k=0;
        while((1<<k)<=i)k++;
        len[i]=k-1;
    }
    int tt;
    scanf("%d",&tt);
    while(tt--){
        work();
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值