洛谷P1016 旅行家的预算 [单调队列]

传送门
题意:给出n个加油站的位置posi和重点t以及每个加油站油的价格vi以及油箱的体积L,求最小花费

题解:如果油箱容量是无限大的那么显然可以直接使用优先队列每经过一个加油站就直接丢进去价格然后每次需要加油就弹出即可,而这里限制了油箱体积为L,就不能无脑无限量地使用最小值,此时维护一个价格单调递增的队列,每次选取队列头的油进行消耗,每次经过加油站,弹出尾部比当前油费贵的油,然后插入体积为L-油箱内剩余的油的体积的当前油站的油即可

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;

struct nod{
    double pos;
    double val;
}no[8];

struct que{
    double val;
    double res;
}q[8];

bool cmp(struct nod a,struct nod b){
    return a.pos<b.pos;
}

int main(){
    double d1,c,d2,p;
    int n;
    scanf("%lf%lf%lf%lf%d",&d1,&c,&d2,&p,&n);
    for(int i=1;i<=n;i++)scanf("%lf%lf",&no[i].pos,&no[i].val);
    sort(no+1,no+1+n,cmp);
    int head=1;
    int tail=0;
    q[++tail].res=c;
    q[tail].val=p;
    double ans=p*c;
    double sum=c;
    int F=1;
    for(int i=1;i<=n;i++){
        if(d1<=no[i].pos){
            double x=(d1-no[i-1].pos)/d2;
            while(head<=tail&&x){
                if(x<q[head].res){
                    q[head].res-=x;
                    x=0;
                    break;
                }
                else{
                    x-=q[head].res;
                    head++;
                }
            }
            if(x)F=0;
            while(head<=tail){
                ans-=q[head].res*q[head].val;
                head++;
            }
        }
        else{
            double x=(no[i].pos-no[i-1].pos)/d2;
            sum-=x;
            while(head<=tail&&x){
                if(x<q[head].res){
                    q[head].res-=x;
                    x=0;
                    break;
                }
                else{
                    x-=q[head].res;
                    head++;
                }
            }
            if(x){F=0;break;}
            while(head<=tail&&q[tail].val>=no[i].val){
                sum-=q[tail].res;
                ans-=q[tail].res*q[tail].val;
                tail--;
            }
            q[++tail].res=c-sum;
            ans+=(c-sum)*no[i].val;
            q[tail].val=no[i].val;
            sum=c;
        }
    }
    if(F&&d1>no[n].pos){
            double x=(d1-no[n].pos)/d2;
            while(head<=tail&&x){
                if(x<q[head].res){
                    q[head].res-=x;
                    x=0;
                    break;
                }
                else{
                    x-=q[head].res;
                    head++;
                }
            }
            if(x)F=0;
            while(head<=tail){
                ans-=q[head].res*q[head].val;
                head++;
            }
    }
    if(F)printf("%.2f\n",ans);
    else printf("No Solution\n");
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章