bzoj2765[JLOI2010]铁人双项比赛

题意:铁人双项比赛由长跑和骑自行车组成,参赛选手必须先完成k公里的长跑,然后完成r公里的骑车,才能到达终点。参赛选手有的擅长长跑,有的擅长骑车。

如果总赛程s=k+r一定,那么K越大,对擅长长跑的选手越有利;k越小,对擅长骑车的选手越有利。

现在给定总赛程s,以及每个选手长跑和骑车的平均速度,请你求出对于某个指定的选手最有利的k和r。

所谓最有利,是指选择了这个k和r后,该选手可以获得冠军,且领先第2名尽量地多。

讲道理这题应该有SpecialJudge,但是BZOJ是在有多种方案时输出k最小的方案,题面上还没说…WA了一屏....

并不知道半平面交是什么东西(半瓶面胶),我写的是二分答案…首先我们把速度的单位从 千米/小时 转为 秒/千米,然后用i号选手的骑车速度减去n号选手的骑车速度,就表示i号选手和n号选手同时骑单位长度的车,n号选手会领先i号选手多少秒(负值表示n号选手落后i号选手).

接下来我们会发现,如果每长跑1千米n号选手会领先i号选手v1秒,每骑1千米车n号选手会领先i号选手v2秒(v1,v2均可能为负),二分答案时要求n号选手必须领先i号选手不少于ans秒,我们就可以确定一个关于k的不等式k*v1+(s-k)*v2>=ans,这里只有k未知,所以可以解出这个不等式.

每二分一个答案,一共得到n-1个形如”k>a”或”k<b”的不等式,只要判断这个不等式组有没有解即可.注意v1==v2的地方需要特判.最后一定要注意:输出解的时候k尽量小,所以最后利用二分出的答案解一遍不等式组,输出的时候用k的下界输出..

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=105;
double v1[maxn],v2[maxn];
int s,n;
bool check(double ans){
    double upper=s,lower=0;    
    for(int i=1;i<n;++i){
        if(v1[i]==v2[i]){
            if(s*v1[i]<ans)return false;
        }
        else if(v1[i]<v2[i])upper=min(upper,(ans-v2[i]*s)/(v1[i]-v2[i]));
        else lower=max(lower,(ans-v2[i]*s)/(v1[i]-v2[i]));
    }
    return upper>=lower;
}
void work(double ans){
    double upper=s,lower=0;    
    for(int i=1;i<n;++i){
        if(v1[i]==v2[i])continue;
        else if(v1[i]<v2[i])upper=min(upper,(ans-v2[i]*s)/(v1[i]-v2[i]));
        else lower=max(lower,(ans-v2[i]*s)/(v1[i]-v2[i]));
    }
    printf("%.2f %.2f ",lower,s-lower);
}
int main(){
    scanf("%d%d",&s,&n);
    for(int i=1;i<=n;++i){
        scanf("%lf%lf",v1+i,v2+i);
        v1[i]=3600/v1[i];v2[i]=3600/v2[i];
    }
    for(int i=1;i<n;++i){
        v1[i]-=v1[n];v2[i]-=v2[n];
    }
    double l=-1,r=1e50;
    while(r-l>=1e-8){
        double mid=(l+r)/2.0;
        if(check(mid))l=mid;
        else r=mid;
    }
    
    if(r<0)printf("NO\n");
    else{
        work(r);
        printf("%.0f\n",r);
    }
    return 0;
}

 

posted @ 2016-10-25 07:41  liu_runda  阅读(392)  评论(0编辑  收藏  举报
偶然想到可以用这样的字体藏一点想说的话,可是并没有什么想说的. 现在有了:文化课好难