BZOJ 2328: [HNOI2011]赛车游戏

Hint里的没有数据是肿么回事,仿佛是在刻意地逗我笑

首先这是个贪心题

我们考虑首先让耗油量尽可能地低

上坡段是必须耗油的,速度先置为0

下坡段速度可以提升一下,达到耗油为0即可

平底自然速度为0

然后找到当前速度最小的路段,提升它的速度与次小的平齐,注意不要超过限制

直到提升不了为止,最后结算一下

如果发现最小和次小速度相等就把他们合并了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int N=10000+5;
const double eps=1e-9;
double a,b,f,vmax;
struct Node{
	double v,l;
	bool operator < (const Node &rhs)const{
		return v>rhs.v;
	}
};
int dcmp(double x){
	if(fabs(x)<eps)return 0;
	return x<0?-1:1;
}
double sqr(double x){return x*x;}
int main(){
	//freopen("a.in","r",stdin);
	int T;scanf("%d",&T);
	while(T--){
		int n;scanf("%lf%lf%lf%lf%d",&a,&b,&vmax,&f,&n);
		priority_queue<Node>q;
		bool flag=true;
		for(int i=1;i<=n;i++){
			double x,y;scanf("%lf%lf",&x,&y);
			x/=1000.0;y/=1000.0;
			double l=sqrt(sqr(x)+sqr(y)),s=y/x;
			int d=dcmp(s);
			if(d>0){
				f-=l*b*s;
				q.push((Node){0,l});
				if(dcmp(f)<=0)flag=false;
			}else if(d<0){
				double v=min(-b/a*s,vmax);
				q.push((Node){v,l});
			}else q.push((Node){0,l});
		}
		if(!flag){
			puts("IMPOSSIBLE");
			continue;
		}
		q.push((Node){vmax,0});
		double ans=0;
		while(dcmp(f)>0&&!q.empty()){
			Node t=q.top();q.pop();
			if(!dcmp(t.v-vmax))ans+=t.l/t.v;
			else if(dcmp(t.v-q.top().v)){
				double delta=f/(a*t.l);
				if(dcmp(t.v+delta-q.top().v)>=0){
					Node tt=q.top();q.pop();
					delta=tt.v-t.v;
					q.push((Node){tt.v,t.l+tt.l});
				}else{
					t.v+=delta;
					q.push(t);
				}
				f-=delta*a*t.l;
			}else{
				Node tt=q.top();q.pop();
				q.push((Node){t.v,t.l+tt.l});
			}
		}
		while(!q.empty()){
			Node t=q.top();q.pop();
			ans+=t.l/t.v;
		}
		printf("%.5lf\n",ans);
	}
	return 0;
}


你可能感兴趣的:(BZOJ 2328: [HNOI2011]赛车游戏)