P1016 [NOIP 1999 提高组] 旅行家的预算 方法全解

\(\text{Sol 1.}\)

考虑设计一个退流机制,我们将油设定为只有用了才计算价值,那么每次到一个加油站就直接加满,并且退掉耗费更大的油,然后优先使用价格小的油驶向下一个加油站,这个过程可以用单调队列维护,时间复杂度 \(\Theta(n)\)

#include <bits/stdc++.h>
#define umap unordered_map
#define vint vector<int>
#define ll long long
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define ull unsigned long long
#define uint unsigned int
#define rg register
#define il inline
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define sqr(x) ((x)*(x))
using namespace std;
const int INF=0x3f3f3f3f;
inline int read(){
    int w=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        w=(w<<1)+(w<<3)+(ch^48);
        ch=getchar();
    }
    return w*f;
}
inline void write(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

#define db double
const db eps=1e-9;
const int N=7;
db d1,c,d2;
int n;
struct node{
    db p,d;
}a[10];
db ans;
struct oil{
    db p,rem;
};
int main(){
    #ifndef ONLINE_JUDGE
    //freopen("in.txt","r",stdin);
    #endif
    cin>>d1>>c>>d2>>a[0].p>>n;
    rep(i,1,n) cin>>a[i].d>>a[i].p;
    a[++n]={0,d1};
    deque<oil> Q;
    Q.push_back({a[0].p,c});
    for(int i=1;i<=n;++i){
        db dis=a[i].d-a[i-1].d;
        db add=0;
        while(1){
            if(Q.empty()){
                puts("No Solution");exit(0);
            }
            if(Q.front().rem*d2>=dis){
                ans+=Q.front().p*dis/d2;
                Q.front().rem-=dis/d2;
                add+=dis/d2;
                break;
            }
            else{
                ans+=Q.front().p*Q.front().rem;
                dis-=Q.front().rem*d2;
                add+=Q.front().rem;
                Q.pop_front();
            }
        }
        while(!Q.empty()&&Q.back().p>a[i].p) add+=Q.back().rem,Q.pop_back();
        // for(auto j:Q) add-=j.rem;
        Q.push_back({a[i].p,add});
    }
    printf("%.2lf\n",ans);
    #ifndef ONLINE_JUDGE
    fprintf(stderr,"%f\n",1.0*clock()/CLOCKS_PER_SEC);
    #endif
    return 0;
}

\(\text{Sol 2.}\)

没到一个加油站有几种选择:加满,加到恰好能到下一个加油站。暴力即可,时间复杂度 \(\Theta(2^n)\),实际跑不满。

参考这篇题解

\(\text{Sol 3.}\)

也是贪心,比解法一好想,但个人觉得不如解法一优美。

考虑在当前加油站做的决策,首先至少得到下一个加油站,然后考虑加不加满,目标直指第一个价格更低的加油站,否则找下一个价格最低的,中间过程判无解。

参考这篇题解

posted @ 2025-08-05 20:41  vanueber  阅读(9)  评论(0)    收藏  举报