BZOJ2328: [HNOI2011]赛车游戏

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;
}

 

posted @ 2018-10-15 22:30  符拉迪沃斯托克  阅读(235)  评论(0编辑  收藏  举报
Live2D