虽然我并不知道如何证明,但是背下结论套的话这题就是模板题了。
设第$i$段路骑行速度为$x_i$
$f=sum frac{s_i}{x_i}$
要求最小化$f$
设$g=E_u-sum k_i*(x_i-v_i)^2*s_i$
贪心,当$x_i<v_i$时,存在关于$v_i$对称的$x$使代价不变而答案更优
故$x_i>=v_i$
故当$g$不为0时,一定可以增大$x$使答案更优,即最优解时$g=0$
$f=sum frac{s_i}{x_i}$
$g=E_u-sum k_i*(x_i-v_i)^2*s_i=0$
设$t=f-lambda*g$
根据拉格朗日乘数啥子的,当$t$的偏导为$0$时,$f$取得极值
即
$-frac{s_i}{x_i}+ 2lambda k_i s_i(x_i-v_i)=0$
$x_i>=v_i$,故$lambda$随$x_i$单调
二分$lambda$使$g=0$即可
注意实数二分最好控制次数而不是$eps$
关于二分的上界我比较懵逼,我看有人开到1e5就过了,这个大概要随缘吧……
1 //Achen
2 #include<algorithm>
3 #include<iostream>
4 #include<cstring>
5 #include<cstdlib>
6 #include<vector>
7 #include<cstdio>
8 #include<queue>
9 #include<cmath>
10 #include<set>
11 #include<map>
12 #define Formylove return 0
13 #define For(i,a,b) for(int i=(a);i<=(b);i++)
14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
15 #define eps 1e-15
16 const int N=1e4+7;
17 typedef long long LL;
18 typedef double db;
19 using namespace std;
20 int n;
21 db E,s[N],k[N],v[N],x[N];
22
23 template<typename T>void read(T &x) {
24 char ch=getchar(); x=0; T f=1;
25 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
26 if(ch=='-') f=-1,ch=getchar();
27 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
28 }
29
30 int dcmp(db x) { return fabs(x)<=eps?0:(x>0?1:-1); }
31
32 void get_x(db lmd) {
33 lmd=1.0/lmd;
34 For(i,1,n) {
35 db l=max(0.0,v[i]),r=1e5;
36 For(ti,1,80) {
37 db mid=(l+r)/2.0;
38 if(dcmp(k[i]*mid*mid*2*(mid-v[i])-lmd)<=0) l=mid;
39 else r=mid;
40 }
41 x[i]=l;
42 }
43 }
44
45 int ck(db lmd) {
46 get_x(lmd);
47 db tp=E;
48 For(i,1,n)
49 tp-=k[i]*(x[i]-v[i])*(x[i]-v[i])*s[i];
50 return dcmp(tp)>=0;
51 }
52
53 int main() {
54 #ifdef ANS
55 freopen(".in","r",stdin);
56 freopen(".out","w",stdout);
57 #endif
58 read(n);
59 scanf("%lf",&E);
60 For(i,1,n)
61 scanf("%lf %lf %lf",&s[i],&k[i],&v[i]);
62 db l=0,r=1e5,lmd;
63 For(ti,1,80) {
64 lmd=(l+r)/2.0;
65 if(ck(lmd)) r=lmd;
66 else l=lmd;
67 }
68 get_x(lmd);
69 db ans=0;
70 For(i,1,n) ans+=s[i]/x[i];
71 printf("%.6lf
",ans);
72 Formylove;
73 }
和上道题一样的模板