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

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

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

2λkix2i(xivi)=1

kisi(xivi)2=E

发现 xv x2(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值