bzoj2765[JLOI2010]鐵人雙項比賽

題意:鐵人雙項比賽由長跑和騎自行車組成,參賽選手必須先完成k千米的長跑,而後完成r千米的騎車,才能到達終點。參賽選手有的擅長長跑,有的擅長騎車。spa

若是總賽程s=k+r必定,那麼K越大,對擅長長跑的選手越有利;k越小,對擅長騎車的選手越有利。code

如今給定總賽程s,以及每一個選手長跑和騎車的平均速度,請你求出對於某個指定的選手最有利的k和r。blog

所謂最有利,是指選擇了這個k和r後,該選手能夠得到冠軍,且領先第2名儘可能地多。ci

講道理這題應該有SpecialJudge,可是BZOJ是在有多種方案時輸出k最小的方案,題面上還沒說…WA了一屏....it

並不知道半平面交是什麼東西(半瓶面膠),我寫的是二分答案…首先咱們把速度的單位從 公里/小時 轉爲 秒/公里,而後用i號選手的騎車速度減去n號選手的騎車速度,就表示i號選手和n號選手同時騎單位長度的車,n號選手會領先i號選手多少秒(負值表示n號選手落後i號選手).io

接下來咱們會發現,若是每長跑1公里n號選手會領先i號選手v1秒,每騎1公里車n號選手會領先i號選手v2秒(v1,v2都可能爲負),二分答案時要求n號選手必須領先i號選手很多於ans秒,咱們就能夠肯定一個關於k的不等式k*v1+(s-k)*v2>=ans,這裏只有k未知,因此能夠解出這個不等式.class

每二分一個答案,一共獲得n-1個形如」k>a」或」k<b」的不等式,只要判斷這個不等式組有沒有解便可.注意v1==v2的地方須要特判.最後必定要注意:輸出解的時候k儘可能小,因此最後利用二分出的答案解一遍不等式組,輸出的時候用k的下界輸出..di

#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;
}
相關文章
相關標籤/搜索