记录编号 117629 评测结果 AAAAAAAAAA
题目名称 [HNOI 2011] 赛车游戏 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.248 s
提交时间 2014-08-30 18:53:14 内存使用 0.71 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<iomanip>
using namespace std;
const double eps=1e-18,epsf=1e-7,INF=1e9;
const int SIZEN=10010;
int N;
double a,b,vmax,f;
double L[SIZEN]={0},s[SIZEN]={0};
double fd[SIZEN]={0},fe[SIZEN]={0},ft[SIZEN]={0};//每段路的最小导数,最小油耗,最长耗时
double mnd,mxd;//最小和最大的可能导数
double stt;
bool legal[SIZEN]={0};
/*
若某段路耗油E,则v=(E/L-bs)/a
t=(L^2a)/(E-bsL)
f'(t)=-L^2a/(E-bsL)^2
*/
inline double sqr(double x){return x*x;}
double e_calc_d(double E,int i){
	double ans=-L[i]*L[i]*a/((E-b*s[i]*L[i])*((E-b*s[i]*L[i])));
	return fabs(ans)>eps?ans:0;
}
double e_calc_t(double E,int i){
	double ans=L[i]*L[i]*a/(E-b*s[i]*L[i]);
	return fabs(ans)>eps?ans:0;
}
double e_calc_v(double E,int i){
	double ans=(E-b*s[i]*L[i])/(a*L[i]);
	return fabs(ans)>eps?ans:0;
}
double d_calc_e(double d,int i){
	double ans=sqrt(-L[i]*L[i]*a/d)+b*s[i]*L[i];
	return fabs(ans)>eps?ans:0;
}
void calc(double md,double &t,double &e){
	//最小导数为md,计算时间和油耗
	t=e=0;
	for(int i=1;i<=N;i++){
		if(fd[i]>=md){
			t+=ft[i];
			e+=fe[i];
			continue;
		}
		double E=d_calc_e(md,i);
		if(e_calc_v(E,i)>=vmax){
			t+=L[i]/vmax;
			e+=L[i]*(a*vmax+b*s[i]);
			continue;
		}
		t+=e_calc_t(E,i);
		e+=E;
	}
}
void work(void){
	double l=mnd,r=mxd;
	double tsum,esum;
	int cnt=0;
	while(cnt<80){
		double mid=(l+r)/2.0;
		calc(mid,tsum,esum);
		if(tsum>24.0){//跑的时间太长了,说明导数太小
			l=mid;
		}
		else if(esum>f){//耗油太多了,说明导数太大
			r=mid;
		}
		else if(esum<f){//耗油太少了,说明导数太小
			l=mid;
		}
		cnt++;
	}
	calc((l+r)/2.0,tsum,esum);
	tsum+=stt;
	if(tsum>24.0||esum>f+epsf) printf("IMPOSSIBLE\n");
	else printf("%.5lf\n",tsum);
}
void prepare(void){
	//当最小导数最小时,令所有段均跑24h或不耗油
	mnd=INF,mxd=-INF;
	stt=0;
	for(int i=1;i<=N;i++){
		if(s[i]<0&&(-s[i]*b/a)>=vmax){
			stt+=L[i]/vmax;
			legal[i]=false;
		}
		else legal[i]=true;
	}
	int tot=0;
	for(int i=1;i<=N;i++){
		if(legal[i]){
			tot++;
			L[tot]=L[i];s[tot]=s[i];
		}
	}
	N=tot;
	double E;
	for(int i=1;i<=N;i++){
		if(s[i]<0) E=0;
		else E=L[i]*(a*L[i]/24.0+b*s[i]);//跑24h的油耗
		fe[i]=E;
		fd[i]=e_calc_d(E,i);
		ft[i]=e_calc_t(E,i);
		mnd=min(mnd,fd[i]);
	}
	//当最小导数最大时,令所有段均耗掉所有油
	//这里没考虑vmax,应该没问题......
	for(int i=1;i<=N;i++){
		mxd=max(mxd,e_calc_d(f,i));
	}
}
bool able_pass(void){
	double sum=0;
	for(int i=1;i<=N;i++){
		if(s[i]>=0) sum+=b*s[i]*L[i];
	}
	if(sum>epsf&&sum>=f-epsf) return false;
	return true;
}
void read(void){
	scanf("%lf%lf%lf%lf",&a,&b,&vmax,&f);
	scanf("%d",&N);
	double x,y;
	for(int i=1;i<=N;i++){
		scanf("%lf%lf",&x,&y);
		L[i]=sqrt(x*x+y*y)/1000.0;
		s[i]=y/x;
	}
}
int main(){
	freopen("carrace.in","r",stdin);
	freopen("carrace.out","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		read();
		if(!able_pass()) printf("IMPOSSIBLE\n");
		else{
			prepare();
			work();
		}
	}
	return 0;
}