BZOJ2876: [Noi2012]骑行川藏(拉格朗日乘子法)

传送门

题解:
感觉自己是写错了的,好像bzoj的spj有问题。反正这东西没什么用难得改了

拉格朗日乘子法
题解1
讲得已经很好了,大概是这样:
有函数 f(X),g(X) f ( X ) , g ( X ) ,其中 X X n维向量。

那么
f(X) f ( X ) 取最值时的梯度向量与 g(X) g ( X ) 的梯度向量平行(证明见上面的连接)

而梯度向量的每一维为 xi x i 的偏导数,那么就有 n+1 n + 1 个方程直接解开就好了。

用二分解方程时间复杂度 O(nlog2n) O ( n log 2 ⁡ n )

#include <bits/stdc++.h>
#define rdd(x) scanf("%d",&x)
#define rdf(x) cin>>x
#define DB long double
using namespace std;

const int N=1e5+50;
const DB eps=1e-9;

int n;
DB E,s[N],k[N],v[N],ans[N];

inline DB calc(int id,DB x,DB val) {
    return 2.0*val*k[id]*x*x*(x-v[id]);
}

inline void solve(int id,DB &x,DB val) {
    DB l=((v[id]>0)?v[id]:0),r=1e9;
    for(int i=1;i<=70;i++) {
        DB mid=(l+r)/2.0;
        if(calc(id,mid,val)>-1) l=mid;
        else r=mid;
    }
    x=l; return;
}

inline bool check(DB val) {
    for(int i=1;i<=n;i++)
        solve(i,ans[i],val);
    DB res=0;
    for(int i=1;i<=n;i++) res+=s[i]*k[i]*(ans[i]-v[i])*(ans[i]-v[i]);
    if(res>E) return false;
    return true;
}

int main() {
    rdd(n), rdf(E);
    for(int i=1;i<=n;i++) rdf(s[i]),rdf(k[i]),rdf(v[i]);
    DB l=-1e9,r=0;
    for(int i=1;i<=70;i++) {
        DB mid=(l+r)/2.0;
        if(check(mid)) l=mid;
        else r=mid;
    }   
    check(l);
    DB res=0;
    for(int i=1;i<=n;i++) res+=s[i]/ans[i];
    printf("%.8f",(double)res);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值