P2179-[NOI2012]骑行川藏【导数,二分】
正題
題目鏈接:https://www.luogu.com.cn/problem/P2179
題目大意
給出EEE和nnn個si,ki,uis_i,k_i,u_isi?,ki?,ui?求一個序列viv_ivi?滿足
∑i=1nkisi(vi?ui)2≤E\sum_{i=1}^nk_is_i(v_i-u_i)^2\leq Ei=1∑n?ki?si?(vi??ui?)2≤E
的情況下最小化
∑i=1nsivi\sum_{i=1}^n\frac{s_i}{v_i}i=1∑n?vi?si??
1≤n≤1041\leq n\leq 10^41≤n≤104
解題思路
洛谷題解上一個十分神奇的做法看起來。(主要是看不懂拉格朗日乘數法/kk)
首先考慮對于段路的行駛時間ti=sivit_i=\frac{s_i}{v_i}ti?=vi?si??,我們可以畫出消耗的能量EEE和tit_iti?的函數。
對于函數f(E)=tif(E)=t_if(E)=ti?不難發現的是在vi≥uiv_i\geq u_ivi?≥ui?的情況下EEE越小這個函數對應位置的導數越小。
也就是消耗單位能量減少的時間也就越少,性價比就越低。而我們現在要給每段路分配一個tit_iti?使得消耗能量和等于EEE且tit_iti?和最小的話。
根據貪心的思想有選出若干個的tit_iti?滿足對應位置的導數相等。
那么我們就找到了所有路的共性,考慮二分這個導數,但是我們先對這個函數f(v)=tEf(v)=\frac{t}{E}f(v)=Et?求個導。
t′=?svi2,E′=2kisi(vi?ui)t'=-\frac{s}{v_i^2},E'=2k_is_i(v_i-u_i)t′=?vi2?s?,E′=2ki?si?(vi??ui?)
f′(v)=t′E′=?s2kisivi2(vi?ui)f'(v)=\frac{t'}{E'}=-\frac{s}{2k_is_iv_i^2(v_i-u_i)}f′(v)=E′t′?=?2ki?si?vi2?(vi??ui?)s?
然后我們二分出f′(vi)=xf'(v_i)=xf′(vi?)=x然后再二分出對應的速度viv_ivi?就好了。
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e4+10; int n;double E,s[N],k[N],v[N]; double getv(double x,int p){double l=max(v[p],0.0),r=100000;for(int i=1;i<=100;i++){double V=(l+r)/2.0;if(-2.0*k[p]*V*V*x*(V-v[p])<1.0)l=V;else r=V;}return (l+r)/2.0; } double check(double x){double E=0;for(int i=1;i<=n;i++){double V=getv(x,i);E+=k[i]*s[i]*(V-v[i])*(V-v[i]);}return E; } int main() {scanf("%d",&n);scanf("%lf",&E);for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&s[i],&k[i],&v[i]);double l=-1e5,r=0;for(int i=1;i<=100;i++){double mid=(l+r)/2.0;if(check(mid)<=E)l=mid;else r=mid;}double mid=(l+r)/2.0,ans=0;for(int i=1;i<=n;i++)ans+=s[i]/getv(mid,i);printf("%.12lf\n",ans);return 0; }總結
以上是生活随笔為你收集整理的P2179-[NOI2012]骑行川藏【导数,二分】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win10系统屏幕保护色的设置方法
- 下一篇: P3288-[SCOI2014]方伯伯运