题意:在满足∀i,vi≥0且∑ni=1kisi(vi−ti)2≤E前提下最小化∑ni=1si/vi。
学习了一下拉格朗日橙子乘子法。
对于函数F(x1,x2,⋯,xn)和G(x1,x2,⋯,xn),在满足G=c(c为常数)的前提下求F的最小值。我们直观地想象,所有极值点一定满足
这其中的λ就是Lagrange Multiplier里的multiplier啦。
回到这个题。显然每段路能跑得越快越好,最后一定可以把体力给浪完,所以不等号可以换成等号。
这样就变成了G(v1...)=E,最小化F(v1...)=∑ni=1si/vi。
考虑应用拉格朗日乘子法,有
−1v2i=2λki(vi−ti),∀i∈[1,n]
回想题目里的性质,首先vi一定非负,其次vi一定不小于ti。这些方程的左边是在二四象限的双曲线,右边是一条直线,因为vi≥0所以一定只有一个交点且λ<0。因此我们可以知道对于所有λ<0每个方程都有唯一解。现在我们只需解出满足G=E的λ。同样从图像出发,当λ增大时,vi也会增大,使得G一定增大,因此
至此,我们只需要二分λ的值,然后解出每个vi的值,判断G与
时间复杂度
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (int i = a, _ = b; i <= _; i ++)
const int N = 10007;
const double eps = 1e-14;
#define fuck(a,b,x) a*sqr(x)*(x-b)+1
inline double sqr(double x) { return x * x; }
double s[N], k[N], t[N], E;
int n;
double solve(double a, double b) {
double l = 0, r = 1e6;
while (r - l > eps) {
double m1 = l + (r - l) / 3;
double m2 = r - (r - l) / 3;
double fl = fuck(a, b, l);
double fr = fuck(a, b, r);
double f1 = fuck(a, b, m1);
double f2 = fuck(a, b, m2);
if (fl * f1 < 0) r = m1;
else if (fl * f2 < 0) r = m2;
else if (f1 * fr < 0) l = m1;
else if (f2 * fr < 0) l = m2;
else assert(0);
}
return l;
}
double get(double l) {
double ret = 0;
rep (i , 1 , n) {
double x = solve(2 * k[i] * l, t[i]);
ret += k[i] * sqr(x - t[i]) * s[i];
}
return ret;
}
int main() {
cin >> n >> E;
rep (i , 1 , n) cin >> s[i] >> k[i] >> t[i];
double l = -1e10, r = 0;
while (r - l > eps) {
double m = l + (r - l) / 2;
if (get(m) >= E)
r = m;
else
l = m;
}
double ans = 0;
rep (i , 1 , n) {
double x = solve(2 * k[i] * l, t[i]);
ans += s[i] / x;
}
printf("%.6lf\n", ans);
return 0;
}