[拉格朗日乘数法 二分] BZOJ 2876 [Noi2012]骑行川藏

来源:互联网 发布:找游戏的软件 编辑:程序博客网 时间:2024/04/30 03:52

拉格朗日乘数法 ACdreamers
[Math & Algorithm] 拉格朗日乘数法

首先那个能量肯定是要花完的,就变成一个限制了,乘上拉格朗日乘子,求偏导,变成了

2λkix2i(xivi)=1

kisi(xivi)2=E

发现 xvx2(xv) 是单调增的,那么二分λ就好了

#include<cstdio>#include<cstdlib>#include<algorithm>#include<iostream>#include<cmath>using namespace std;typedef long double ld;const int N=10005;const ld eps=1e-12;int n; ld E,s[N],k[N],V[N];ld v[N];inline ld Calc(ld mid){  ld ret=0;  for (int i=1;i<=n;i++){    ld L=max(V[i],(ld)0.0),R=1e9,MID;    while (R-L>eps){      MID=(L+R)/2;      if (2*mid*k[i]*MID*MID*(MID-V[i])>1.0)    R=MID;      else    L=MID;     }    v[i]=(L+R)/2;    ret+=k[i]*s[i]*(v[i]-V[i])*(v[i]-V[i]);  }  return ret;}int main(){  freopen("t.in","r",stdin);  freopen("t.out","w",stdout);  cin>>n>>E;  for (int i=1;i<=n;i++) cin>>s[i]>>k[i]>>V[i];  ld L=0,R=1e9,MID;  while (R-L>eps){    ld ret=Calc(MID=(L+R)/2);    if (ret>=E)      L=MID;    else      R=MID;  }  Calc((L+R)/2);  ld ans=0;  for (int i=1;i<=n;i++)    ans+=s[i]/v[i];  printf("%.10lf\n",(double)ans);  return 0;}
阅读全文
0 0