题解 P3218 【[HNOI2011]赛车游戏】
这道题乍一看挺复杂的,其实思路理清之后还是比较简单的吧。
首先我们可以手玩几组数据,发现取到最优解总是在每一段的速度都比较平均的情况下取到,因此我们不妨大胆猜想:
最优解在速度基本相同的情况下最优。
大概的证明如下(转自http://blog.163.com/bill125_zjh/blog/static/231801006201441025744282/):
反正我是看不懂QwQ,但是我们学的是OI不是数学,所以我们只要有猜想就好了对吧(雾
好的那么有了这两个个性质后,我们再继续观察题目中的耗油量的表达式:
其中
结合以上,我们可以二分整段速度的最大值,再由这个速度计算出最优解就好了。
计算这里还有一个细节,若
但这个时候显然速度是可以更大的,
由
这个时候
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-15;
const int N=10010;
struct Node{
double x,y,k,len;
inline void init(){
scanf("%lf%lf",&x,&y);
k=y/x,x/=1000.0,y/=1000.0,
len=sqrt(x*x+y*y);
}
}c[N];
int T,n;
double a,b,mxv,f;
inline bool ck(double mid){
double res=0.0;
for(int i=1;i<=n;++i){
res+=max(a*mid+b*c[i].k,0.0)*c[i].len;
if(res+eps>=f) return 0;
}return 1;
}
inline double calc(double v){
double res=0.0;
for(int i=1;i<=n;++i){
double tmp=a*v+c[i].k*b;
if(tmp<=eps){
double vv=(-b*c[i].k)/a;
vv=min(vv,mxv);
res+=c[i].len/vv;
}else{
if(v<=eps) return 0;
res+=c[i].len/v;
}
}
return res;
}
inline void sol(){
double l=0,r=mxv,mid;
int t=0;
while(t<1000){
mid=(l+r)/2;
if(ck(mid)) l=mid;
else r=mid;
++t;
}
double res=calc(l);
if(res<=eps) puts("IMPOSSIBLE");
else printf("%.5lf\n",res);
}
int main(){
if(fopen("test.in","r")){
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
}
scanf("%d",&T);
while(T--){
scanf("%lf%lf%lf%lf%d",&a,&b,&mxv,&f,&n);
for(int i=1;i<=n;++i) c[i].init();
sol();
}
}