【BZOJ】【2765】【JLOI2010】鐵人雙項比賽

計算幾何/半平面交


  原本我是想去寫POJ 1755的,而後想起了這道跟它很像的題,但應該是弱化版,因此就先寫了這個……php

  咱們能夠發現每一個人的總用時,與k是呈一次函數關係的:$time_i=\frac{k}{Vrun_i}+\frac{S-k}{Vride_i}$ios

  然而咱們要找的是某個k,使得$min(time_n-time_i)$最大ide

  那麼就是一個線性規劃問題了……這個也能夠用半平面交來作……(蒟蒻並不會單純形)函數

  下面的部分爲了偷懶簡潔我就用$a_i$和$b_i$來代替兩種速度……spa

  我一開始想的作法是:維護一個$y=(\frac{1}{a_i}-\frac{1}{b_i})*x+\frac{S}{b_i}$的最小值(上凸殼?),而後因爲線性分段函數的極值必定在分界點處取到(BZOJ 1038 瞭望塔),因此能夠枚舉分界點計算答案。unix

  然而不會寫……後來膜拜了lyd神犇的代碼,發現:code

    這題$n\leq 100$,因此找到可能成爲分界點的點,即全部直線的交點,暴力更新答案就行了……blog

    而後還有一個地方是將不等式從新變形了一下,將第n條直線直接減到前面n-1條直線中……ip

  無限ym……ci

 1 /**************************************************************
 2     Problem: 2765
 3     User: Tunix
 4     Language: C++
 5     Result: Accepted
 6     Time:40 ms
 7     Memory:1276 kb
 8 ****************************************************************/
 9  
10 //BZOJ 2765
11 #include<cmath>
12 #include<cstdio>
13 #include<cstring>
14 #include<cstdlib>
15 #include<iostream>
16 #include<algorithm>
17 #include<iomanip>
18 #define rep(i,n) for(int i=0;i<n;++i)
19 #define F(i,j,n) for(int i=j;i<=n;++i)
20 #define D(i,j,n) for(int i=j;i>=n;--i)
21 using namespace std;
22  
23 const int N=110;
24 /*******************template********************/
25 typedef long double lf;
26 #define eps 1e-12
27 int n,num;
28 lf a[N],b[N],c[N],d[N],S,anst,ansk;
29  
30 void calc(lf k){
31     lf t=1e100;
32     F(i,1,n-1) t=min(t,k*c[i]+d[i]);
33     if (t>anst) anst=t,ansk=k;
34 }
35  
36 int main(){
37 #ifndef ONLINE_JUDGE
38     freopen("2765.in","r",stdin);
39 //  freopen("2765.out","w",stdout);
40 #endif
41     cin >>S>>n;
42     F(i,1,n) cin >> a[i] >> b[i];
43     F(i,1,n-1){
44         c[i]=1/a[i]-1/b[i]-1/a[n]+1/b[n];
45         d[i]=S/b[i]-S/b[n];
46     }
47  
48     anst=-1e100;
49     F(i,1,n-1) F(j,i+1,n-1){
50         if (fabs(c[i]-c[j])<eps) continue;
51         lf k=(d[j]-d[i])/(c[i]-c[j]);
52         if (k<eps || k>S-eps) continue;
53         calc(k);
54     }
55     calc(0); calc(S);
56     anst*=3600;
57     if (anst<-eps) puts("NO");
58     else{
59         if (anst<eps) anst=0;
60         cout<<setprecision(2)<<fixed<<ansk<<' '<<S-ansk<<' ';
61         cout<<setprecision(0)<<fixed<<anst<<endl;
62     }
63     return 0;
64 }
View Code

2765: [JLOI2010]鐵人雙項比賽

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 477  Solved: 117
[Submit][Status][Discuss]

Description

鐵 人雙項比賽是吉林教育學院的一項傳統體育項目。該項目比賽由長跑和騎自行車組成,參賽選手必須先完成k千米的長跑,而後完成r千米的騎車,才能到達終點。 每一個參賽選手所擅長的項目不一樣,有的擅長長跑,有的擅長騎車。若是總賽程s=k+r必定,那麼K越大,對擅長長跑的選手越有利;k越小,對擅長騎車的選手 越有利。
 
如今給定總賽程s,以及每一個選手長跑和騎車的平均速度,請你求出對於某個指定的選手最有利的k和r。所謂最有利,是指選擇了這個k和r後,該選手能夠得到冠軍,且領先第2名儘可能地多。

Input

你的程序從文件讀入輸入數據。
輸入的第一行是兩個正整s和n,s表示總賽程(單位爲千米,s≤231),n表示參賽總人數(2≤n≤100)。
接下來的n行每行是兩個實數,分別表示每一個選手長跑的平均速度和騎車的平均速度(單位爲公里/小時)。
第n個選手就是指定的選手,你的任務是求出對他最有利的k和r。

Output

 
你的程序的輸出包括三個數k,r, t,分別表示對第n號選手最有利的k和r(浮點數,保留小數點後2位),以及在選擇k和r的狀況下,第n號選手最多能夠領先第2名多少秒(四捨五入到整數);若是另外一個選手和該選手並列第一,則t i=0。假若不管選擇什麼k,r都不能使第n號選手獲勝,則輸出「NO」。

Sample Input

100 3
10.0 40.0
20.0 30.0
15.0 35.0

Sample Output

14.29 85.71 612

HINT

Source

[ Submit][ Status][ Discuss]
相關文章
相關標籤/搜索