BZOJ2328: [HNOI2011]赛车游戏
Description
题解Here!
一开始被题面那一长串的描述吓到了,一直没敢做。。。
然后尝试着硬着头皮读懂题面。
然后。。。这不是贪心么???
从耗油量最少开始慢慢贪心地调整。
对于上坡,速度设为$0$,但是免不了耗油,这一部分的耗油先减掉。
对于下坡,速度在不耗油的前提下设到最大(但是不能超过$vmax$)。
对于平路,速度设为$0$。
然后我们用一个优先队列来维护这些线段,每次取出速度最小的段,如果它的速度和次小的速度一样就合并起来,否则将它的速度提升到和次小的速度一样。
当然这是在油够用的前提下,如果油不够用就提到能提到的最高速率。
这样做直到用光油或者都打到$vmax$时结束。
证明?$\tan(\frac{\pi}{2}+k\pi),k\in Z$。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<queue> #define eps (1e-8) using namespace std; int n; double A,B,maxn,f; bool flag; struct node{ double oil,dis; friend bool operator <(const node &p,const node &q){ return p.oil>q.oil; } }; priority_queue<node> q; inline int check(double x){ if(fabs(x)<eps)return 0; return (x>0?1:-1); } void work(){ if(!flag){ printf("IMPOSSIBLE\n"); while(!q.empty())q.pop(); return; } double w,ans=0; node u,v; q.push((node){maxn,0}); while(check(f)>0&&!q.empty()){ u=q.top(); q.pop(); v=q.top(); if(check(u.oil-maxn)==0)ans+=u.dis/u.oil; else if(check(u.oil-v.oil)!=0){ w=f/(A*u.dis); if(check(u.oil-v.oil+w)>=0){ w=v.oil-u.oil; q.pop(); q.push((node){v.oil,u.dis+v.dis}); } else{ u.oil+=w; q.push(u); } f-=A*w*u.dis; } else{ q.pop(); q.push((node){v.oil,u.dis+v.dis}); } } while(!q.empty()){ u=q.top(); q.pop(); ans+=u.dis/u.oil; } printf("%.5lf\n",ans); } void init(){ double x,y,w,l; scanf("%lf%lf%lf%lf%d",&A,&B,&maxn,&f,&n); flag=true; for(int i=1;i<=n;i++){ scanf("%lf%lf",&x,&y); x/=1000.0;y/=1000.0; w=y/x; l=sqrt(x*x+y*y); if(check(w)>0){ f-=w*B*l; q.push((node){0,l}); if(check(f)<=0)flag=false; } else if(check(w)<0)q.push((node){min(-w*B/A,maxn),l}); else q.push((node){0,l}); } } int main(){ int t; scanf("%d",&t); while(t--){ init(); work(); } return 0; }