zoj 3699 Dakar Rally
2013-04-26 14:53
176 查看
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3699
题目大意:
有n段路,从左到右编号1~n,只有通过一段路才会耗油,每段路的最左边有一个加油站,第i段路的加油站的邮费pi、长度是mi、单位耗油ci。
给定邮箱容量cap,问从左到右通过n段路的最小耗油量。
所有正整数不超过10^5.
题目思路:
很容易想到贪心。
设现在在第i个加油站,如果加满汽油,可以开到第j个加油站(通过i~j-1段路)。
(1)如果i~j之间有一个加油站的费用小于等于pi,假设为第k加油站,那么显然,我们在第i个加油站加的油只需要够开到第k个加油站即可,而非加满,而这个第k个加油站也不是min{pi~pj},而是距离第i个加油站最近且油费小于等于pi的。
(2)如果i~j之间所有加油站的费用大于pi呢,那么我们显然要加满油,但是下一次加油在哪一个站呢?
会不会是pk=min{pi~pj}(i~j之间油费最小的那个站)这个加油站呢?
假设不是,而是px。
1、如果x<k,显然不是最优的,一个很简单的例子,假设还需要在i站加满后,还需要y油能开到终点,因为x<k,那么在k能添加的油肯定比在x的多,假设都能添加y油,那么y*px > y*pk,所以花费更大,不是最优的。
2、如果x>k,同上面的例子,如果在k能够添加y油,那么显然在k是更优的,如果不能够添加y油呢?那么我们在x添加y又,则花费y*px,但是假设在k添加了y'油使得,剩余y''油在x添加,那么花费y'*pk+y''*px < y*px,所以在x处也不是最优的。
因此可证在k处最优。
证明写起来有点烦,其实在草稿纸上画画很清晰的。
而还需要解决的一个问题就是如果按照规则找到可达的最优点,因为数据最大是10^5,我是用线段树优化的。
代码:
题目大意:
有n段路,从左到右编号1~n,只有通过一段路才会耗油,每段路的最左边有一个加油站,第i段路的加油站的邮费pi、长度是mi、单位耗油ci。
给定邮箱容量cap,问从左到右通过n段路的最小耗油量。
所有正整数不超过10^5.
题目思路:
很容易想到贪心。
设现在在第i个加油站,如果加满汽油,可以开到第j个加油站(通过i~j-1段路)。
(1)如果i~j之间有一个加油站的费用小于等于pi,假设为第k加油站,那么显然,我们在第i个加油站加的油只需要够开到第k个加油站即可,而非加满,而这个第k个加油站也不是min{pi~pj},而是距离第i个加油站最近且油费小于等于pi的。
(2)如果i~j之间所有加油站的费用大于pi呢,那么我们显然要加满油,但是下一次加油在哪一个站呢?
会不会是pk=min{pi~pj}(i~j之间油费最小的那个站)这个加油站呢?
假设不是,而是px。
1、如果x<k,显然不是最优的,一个很简单的例子,假设还需要在i站加满后,还需要y油能开到终点,因为x<k,那么在k能添加的油肯定比在x的多,假设都能添加y油,那么y*px > y*pk,所以花费更大,不是最优的。
2、如果x>k,同上面的例子,如果在k能够添加y油,那么显然在k是更优的,如果不能够添加y油呢?那么我们在x添加y又,则花费y*px,但是假设在k添加了y'油使得,剩余y''油在x添加,那么花费y'*pk+y''*px < y*px,所以在x处也不是最优的。
因此可证在k处最优。
证明写起来有点烦,其实在草稿纸上画画很清晰的。
而还需要解决的一个问题就是如果按照规则找到可达的最优点,因为数据最大是10^5,我是用线段树优化的。
代码:
#include <stdlib.h> #include <string.h> #include <stdio.h> #include <ctype.h> #include <math.h> #include <stack> #include <queue> #include <map> #include <set> #include <vector> #include <string> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ls rt<<1 #define rs ls|1 #define lson l,mid,ls #define rson mid+1,r,rs #define middle (l+r)>>1 #define clr_all(x,c) memset(x,c,sizeof(x)) #define clr(x,c,n) memset(x,c,sizeof(x[0])*(n+1)) #define eps (1e-8) #define MOD 1000000007 #define INF 0x3f3f3f3f #define PI (acos(-1.0)) #define E 2.7182818284590452353602874713527 #pragma comment(linker, "/STACK:102400000,102400000") template <class T> T _max(T x,T y){return x>y? x:y;} template <class T> T _min(T x,T y){return x<y? x:y;} template <class T> T _abs(T x){return (x < 0)? -x:x;} template <class T> T _mod(T x,T y){return (x > 0)? x%y:((x%y)+y)%y;} template <class T> void _swap(T &x,T &y){T t=x;x=y;y=t;} template <class T> void getmax(T& x,T y){x=(y > x)? y:x;} template <class T> void getmin(T& x,T y){x=(x<0 || y<x)? y:x;} int TS,cas=1; const int M=100000+5; int n; struct node{ ll m,c,p; void read(){scanf("%lld%lld%lld",&m,&c,&p);c*=m;} }rou[M]; ll sum[M],mmin[M<<2],pos[M<<2],cap,last,oil; int far[M]; int bs(ll *sum,int l,int r,ll key){ int ret=-1; while(l<=r){ int mid=middle; if(sum[mid]<=key) l=(ret=mid)+1; else r=mid-1; } return ret; } void pushUp(int rt){ if(mmin[ls]<=mmin[rs]){ mmin[rt]=mmin[ls],pos[rt]=pos[ls]; }else{ mmin[rt]=mmin[rs],pos[rt]=pos[rs]; } } void build(int l,int r,int rt){ if(l==r){ mmin[rt]=rou[l].p; pos[rt]=l; return; } int mid=middle; build(lson),build(rson); pushUp(rt); } int query(int l,int r,int rt,int L,int R,ll p){ if(L<=l && r<=R){ if(l==r) return l; if(mmin[rt]>p) return pos[rt]; else{ int mid=middle; if(mmin[ls]<=p) return query(lson,L,R,p); if(mmin[rs]<=p) return query(rson,L,R,p); } } int mid=middle; if(R<=mid) return query(lson,L,R,p); if(mid<L) return query(rson,L,R,p); int r1=query(lson,L,mid,p); int r2=query(rson,mid+1,R,p); if(rou[r1].p<=p) return r1; else if(rou[r2].p<=p) return r2; else return (rou[r1].p <= rou[r2].p)? r1:r2; } void run(){ int i,j; scanf("%d%d",&n,&cap); for(i=1,sum[0]=0;i<=n;i++){ rou[i].read(); sum[i]=sum[i-1]+rou[i].c; //printf("sum[%d] = %lld\n",i,sum[i]); } for(i=1;i<=n;i++){ far[i]=bs(sum,i,n,cap+sum[i-1])+1; if(far[i]==0) return void(puts("Impossible")); } int nn; rou[nn=n+1].p=0; build(1,nn,1); for(i=1,oil=0,last=0;i<=n;i=j){ j=query(1,nn,1,i+1,far[i],rou[i].p); int tot= (rou[i].p < rou[j].p)? cap:sum[j-1]-sum[i-1]; oil+=(tot-last)*rou[i].p; //printf("%d : oil = %lld\n",i,oil); last=tot-(sum[j-1]-sum[i-1]); } printf("%lld\n",oil); } void preSof(){ } int main(){ //freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); preSof(); //run(); //while((~scanf("%d",&n))) run(); for(scanf("%d",&TS);cas<=TS;cas++) run(); return 0; }
相关文章推荐
- ZOJ 3699 Dakar Rally
- ZOJ 3699 Dakar Rally 解题报告
- ZOJ3699-Dakar Rally
- ZOJ-3699 Dakar Rally 单调队列
- ZOJ 3699 Dakar Rally(贪心)
- ZOJ 3699 Dakar Rally(贪心算法)
- ZOJ 3699 Dakar Rally
- ZOJ 3699 Dakar Rally
- zoj 3699 Dakar Rally(单调队列)
- ZOJ 3699 Dakar Rally
- ZOJ 3699 Dakar Rally
- ZOJ 3703,3700,3699
- ZOJ 3699 (贪心模拟)【加油站类模板】
- zoj 3699 单调队列
- zoj 2172 Symmetric Order
- zoj 1410 Number Sequence
- ZOJ 2314 有上下界的网络流
- zoj 3471 Most Powerful 状压dp(简单)
- ZOJ Problem Set - 1007Numerical Summation of a Series
- zoj 3686 A Simple Tree Problem