1. 程式人生 > 實用技巧 >LG P2179 [NOI2012]騎行川藏

LG P2179 [NOI2012]騎行川藏

Description

蛋蛋非常熱衷於挑戰自我,今年暑假他準備沿川藏線騎著自行車從成都前往拉薩. 川藏線的沿途有著非常美麗的風景,但在這一路上也有著很多的艱難險阻,路況變化多端,而蛋蛋的體力十分有限,因此在每天的騎行前設定好目的地,同時合理分配好自己的體力是一件非常重要的事情. 由於蛋蛋裝備了一輛非常好的自行車,因此在騎行過程中可以認為他僅在克服風阻做功(不受自行車本身摩擦力以及自行車與地面的摩擦力影響). 某一天他打算騎 $n$段路,每一段內的路況可視為相同:

對於第 $i$段路,我們給出有關這段路況的 $3$個引數$s_i,k_i,v_i'$,其中 $s_i$表示這段路的長度,$k_i$表示這段路的風阻係數,$v_i'$表示這段路上的風速($v_i' > 0$表示在這段路上他遇到了順風,反之則意味著他將受逆風影響)。

若某一時刻在這段路上騎車速度為 $v$,則他受到的風阻 大小為 $F=k_i(v-v')^2$(這樣若在長度為 $s$的路程內保持騎行速度 $v$不變,則他消耗能量(做功)$E=k_is_i(v-v')^2$)。

設蛋蛋在這天開始時的體能值是 $E_U$,請幫助他設計一種行車方案,使他在有限的體力內用最短的時間到達目的地。請告訴他最短的時間 $T$是多少。

Solution

先令在順風路段的車速為風速,逆風路段的車速為$0$,這樣可以得到消耗能量的最小值

考慮消耗能量提升速度,從而減少時間

可以作出每個路段的$t-E$影象,發現不同路段消耗單位能量減少的時間不同

貪心地想,每次都選擇單位能量減少時間最多的那條路段,在該路段上花費能量

如此反覆,最終能量耗盡時,所有路段上的$t-E$影象在該路段消耗的$E_i$處切線斜率相等

$$\left \{ \begin{matrix}
E=ks(v-v')^2\\
v=\frac{s}{t}
\end{matrix} \right .$$

解$t$對於$E$的導數,二分該導數

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n;
double e,s[10005],k[10005],v[10005],ans;
double getv(double x,int
i) { double l=max(v[i],0.0),r=100000; while(r-l>=1e-14) { double mid=(l+r)/2; if(2*k[i]*x*mid*mid*(mid-v[i])>-s[i]) { l=mid; } else { r=mid; } } return (l+r)/2; } double check(double x) { double ret=0; for(int i=1;i<=n;i++) { double V=getv(x,i); ret+=k[i]*(V-v[i])*(V-v[i]); } return ret; } int main() { scanf("%d%lf",&n,&e); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&s[i],&k[i],&v[i]); k[i]*=s[i]; } double l=-0x7f7f7f7f,r=0; while(r-l>=1e-14) { double mid=(l+r)/2; if(check(mid)<=e) { l=mid; } else { r=mid; } } for(int i=1;i<=n;i++) { ans+=s[i]/getv(l,i); } printf("%.8lf",ans); return 0; }
[NOI2012]騎行川藏