zoukankan      html  css  js  c++  java
  • 「NOI2012」骑行川藏

    这道题被 yhx-12243 吐槽,但是我还是没考虑全所有的细节……

    这种数学题也是要尽量去推条件的。


    这道题精度要求貌似很高……还是我写丑了?

    根据题意,可以列出式子

    [mathrm{Minimize} sum frac{s_i}{v_i} \ mathrm{s.t.} sum k_i s_i left(v_i - v_i' ight)^2 = E ]

    多元函数求最值,考虑拉格朗日乘数

    [egin{align*} g(v) & = sum k_i s_i left(v_i - v_i' ight)^2 - E \ f(v, lambda) & = sum frac{s_i}{v_i} + lambda g(v) end{align*} ]

    解方程

    [egin{align*} frac{partial f(v, lambda)}{partial v_i} & = - frac{s_i}{v_i^2} + 2 lambda k_i s_i left(v_i - v_i' ight)^2 & = 0\ frac{partial f(v, lambda)}{partial lambda} & = sum k_i s_i left(v_i - v_i' ight)^2 - E & = 0 end{align*} ]

    对于 (v_i) 的偏导,发现 (2 lambda k_i left(v_i - v_i' ight)^2 = 1)

    注意到如果我们的速度 (v_i > v_i')。如果 (v_i < v_i'),那么存在一个 (v = 2v_i' - v_i),那么能量消耗相等,但是速度更快了,明显更优。

    于是将这个条件带入方程,发现 (lambda > 0)

    然后发现当 (lambda) 增大, (v_i) 是单调减的。那么 (g(v)) 也会单调减。所以可以二分 (lambda) 来找到一个满足第二条方程式的解

    然后将得到的解带入就好了。

    关于解出 (v_i),可以二分,也可以迭代。注意迭代的初始解要大,不然会挂。

    注意调参,在精度与速度中权衡。如果没写挂也不会爆 nan 的。

    复杂度 (Oleft( k_1k_2n ight)),其中 (k_1)(lambda) 二分次数, (k_2) 是解方程迭代次数。

    #include <bits/stdc++.h>
    
    const int MAXN = 10010;
    const int STP = 30;
    const int S2 = 150;
    typedef long double ld;
    const ld eps = 1e-12;
    ld ss[MAXN], ks[MAXN], vs[MAXN];
    int n; ld E;
    ld solve(int i, ld l) {
    	ld x = 1e5;
    	ld c = .5 / ks[i] * l;
    	for (int S = 0; S < STP; ++S) {
    		ld func = x * x * (x - vs[i]) - c;
    		ld de = x * (3 * x - 2 * vs[i]);
    		x -= func / de;
    	}
    	return x;
    }
    ld tv[MAXN];
    inline ld pows(ld x) { return x * x; }
    int main() {
    	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
    	std::cin >> n >> E;
    	for (int i = 1; i <= n; ++i) std::cin >> ss[i] >> ks[i] >> vs[i];
    	ld l = 0, r = 1e10;
    	for (int S = 1; S <= S2; ++S) {
    		ld mid = (l + r) / 2;
    		ld sum = 0;
    		for (int i = 1; i <= n; ++i) {
    			tv[i] = solve(i, mid);
    			sum += ks[i] * ss[i] * pows(tv[i] - vs[i]);
    		}
    		sum > E ? r = mid : l = mid;
    	}
    	ld ans = 0;
    	for (int i = 1; i <= n; ++i) ans += ss[i] / tv[i];
    	std::cout << std::fixed << std::setprecision(10) << ans << std::endl;
    	return 0;
    }
    
  • 相关阅读:
    洛谷P3455
    开发人员的奋斗目标
    js判读周末以及节假日
    c#中集成Swagger
    Combo Select – jQuery可搜索下拉框插件
    接口对接 调用与处理方式
    问题集锦
    sql server 自定义函数的使用
    Api接口服务的设计和安全解决方案
    使用Jquery Ajax请求 下载压缩文件
  • 原文地址:https://www.cnblogs.com/daklqw/p/11647974.html
Copyright © 2011-2022 走看看