洛谷 P2209 [USACO13OPEN]燃油经济性Fuel Economy
题目描述
Farmer John has decided to take a cross-country vacation. Not wanting his cows to feel left out, however, he has decided to rent a large truck and to bring the cows with him as well!
The truck has a large tank that can hold up to G units of fuel (1 <= G <= 1,000,000). Unfortunately, it gets very poor mileage: it consumes one unit of fuel for every unit of distance traveled, and FJ has a total of D units of distance to travel along his route (1 <= D <= 1,000,000,000).
Since FJ knows he will probably need to stop to refill his tank several times along his trip, he makes a list of all the N fuel stations along his route (1 <= N <= 50,000). For each station i, he records its distance X_i from the start of the route (0 <= X_i <= D), as well as the price Y_i per unit of fuel it sells (1 <= Y_i <= 1,000,000).
Given this information, and the fact that FJ starts his journey with exactly B units of fuel (0 <= B <= D), please determine the minimum amount of money FJ will need to pay for fuel in order to reach his destination. If it is impossible for him to reach the destination, please output -1. Note that the answer to this problem may not fit into a standard 32-bit integer.
Farmer Jhon 决定去一次跨国旅游度假。为了不让他的奶牛们感到被抛弃,他决定租一辆大卡车来带他的奶牛们一起旅行。
这辆卡车有一个很大的油箱,可以装下G个单位的油(1 <= G <= 1,000,000), 不幸的是,卡车的耗油量也很大,卡车每运动一个单位的距离,就要消耗一个单位的油。Farmer Jhon 要在他的旅程中走D个单位的距离。(1 <= D <= 1,000,000,000)
因为FJ直到他可能要几次在旅途中停下,给油箱加油,所以他把在旅途沿路上的N个加油站的记录做成了表格。对于第i个加油站,他记录了加油站与起点的距离X_i(0 <= X_i <= D),以及加油站中每单位油的价格Y_i(1 <= Y_i <= 1,000,000)。
已知以上所给的信息,以及FJ在路途中实际使用的油的数量B(0 <= B <= D),请计算出FJ到达目的地时花费的油费用的最小值。如果FJ无法到达旅途的终点,那么轻输出-1。本题的答案可能无法使用32位整数储存。
输入输出格式
输入格式:
第1行: 四个整数: N,G,B,D
第2~1+N行: 每一行都有两个整数X_i与Y_i,意义如上所述
输出格式:
一个整数,如果FJ无法到达旅途的终点,那么输出-1,否则输出FJ到达目的地时花费的油费用的最小值。
输入输出样例
4 10 3 17
2 40
9 15
5 7
10 12
174
说明
样例解释:FJ先移动2个单位,然后停下购买2个单位的油(要花费40 x 20)。然后一直前进到距离起点5个单位的地方,此时油箱为空。这时向油箱里加满油(要花费7 x 10)。再向前走5个单位,加2个单位的油(花费12 x 2)。最后一直走到终点。此时总花费是174.
思路:贪心。首先对各个加油站的坐标从小到大排序,然后进行贪心求解。
1.找在能力范围之内所能到达的比当前加油站的油价小的第一个加油站。如果没有就找当前能力范围内油价最小的加油站。
2.跳到上一步找到的加油站。
3.如果在加满油后,所能到达的加油站的油价有比当前便宜的,那么只要加满足够到达那个加油站的油。
4.反之,就加满油。
错因:
1.思路错误:一开始是对价格排的序,找到当前加油站后面所能到达的加油站中油价最小的加油站然后跳过去。但是这样的贪心是不正确的,eg:100 10 1 对这个例子我会从100跳到1花费200,但是如果从100跳到10再跳到1就只花费110。
2.漏下了flag1。
3.判断力所能及的加油站范围判断错误。
4.再3步时,没有考虑不用加油的情况。出现了负数。
吐槽:来给大家看一下提交记录QwQ
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 50002 using namespace std; long long N,G,B,D; long long ans,now,lost,pos; struct nond{ long long x,y; }v[MAXN]; int cmp(nond a,nond b){ return a.x<b.x; } int main(){ cin>>N>>G>>B>>D; for(int i=1;i<=N;i++) cin>>v[i].x>>v[i].y; v[0].x=0;v[0].y=0x7f7f7f7f; v[N+1].x=D;v[N+1].y=0; sort(v+1,v+2+N,cmp); if(v[1].x-v[0].x>B){ cout<<"-1"; return 0; } for(int i=2;i<=N+1;i++) if(v[i].x-v[i-1].x>G){ cout<<"-1"; return 0; } lost=B;now=0;pos=0; while(now!=D){ int num=pos+1; bool flag=0,flag1=0;; for(int i=pos+1;i<=N+1;i++) if(v[i].y<v[pos].y&&v[i].x-now<=lost){ num=i; flag1=1; break; } if(!flag1) for(int i=pos+1;i<=N+1;i++) if(v[i].y<=v[num].y&&v[i].x-now<=lost) num=i; lost-=v[num].x-now; now=v[num].x; pos=num; for(int i=pos+1;i<=N+1;i++) if(v[i].y<v[pos].y&&v[i].x-now<=G){ if(v[i].x-now-lost<=0) ans=ans; else{ ans+=(v[i].x-now-lost)*v[pos].y; lost+=v[i].x-now-lost; } flag=1; break; }else if(v[i].x-now>G) break; if(!flag){ ans+=(G-lost)*v[pos].y; lost=G; } } cout<<ans; }