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.}\)
也是贪心,比解法一好想,但个人觉得不如解法一优美。
考虑在当前加油站做的决策,首先至少得到下一个加油站,然后考虑加不加满,目标直指第一个价格更低的加油站,否则找下一个价格最低的,中间过程判无解。

浙公网安备 33010602011771号