维护凸壳
CDQ
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 100010
using namespace std;
const double eps = 1e-8;
const int inf = 0x7fffffff;
struct opt{
double q, a, b, rate, k;
int pos;
}q[maxn], nq[maxn];
int Filter(double x){
return x > eps ? 1 : (x < -eps ? -1 : 0);
}
struct Point{
double x, y;
bool operator<(const Point& k)const{
return (Filter(x - k.x) < 0) ||
(Filter(x - k.x) == 0 && Filter(y - k.y) < 0);
}
}p[maxn], np[maxn];
double f[maxn];
int st[maxn], n, m;
#define K getk
double K(int i, int j){
if (i == 0) return -inf;
if (j == 0) return inf;
if (Filter(p[i].x-p[j].x) == 0) return -inf;
return (p[i].y - p[j].y) / (p[i].x - p[j].x);
}
void solve(int l, int r){
if(l == r){
f[l] = max(f[l - 1], f[l]);
p[l].x = f[l] / (q[l].a * q[l].rate + q[l].b) * q[l].rate;
p[l].y = f[l] / (q[l].a * q[l].rate + q[l].b);
return;
}
int mid = l + r >> 1, l1 = l, l2 = mid + 1;
for(int i = l; i <= r; i ++)
if(q[i].pos <= mid)nq[l1 ++] = q[i];
else nq[l2 ++] = q[i];
memcpy(q + l, nq + l, sizeof (q[0]) * (r - l + 1));
solve(l, mid);
int top = 0;
for(int i = l; i <= mid; i ++){
while(top >= 2 && Filter(K(i, st[top]) - K(st[top], st[top - 1])) >= 0)
top --;
st[++ top] = i;
}
int j = 1;
for(int i = r; i >= mid + 1; i --){
while(j < top && Filter(q[i].k - K(st[j], st[j + 1])) <= 0)
j ++;
f[q[i].pos] = max(f[q[i].pos], p[st[j]].x * q[i].a + p[st[j]].y * q[i].b);
}
solve(mid + 1, r);
l1 = l, l2 = mid + 1;
for(int i = l; i <= r; i ++){
if((p[l1] < p[l2] || l2 > r) && l1 <= mid)
np[i] = p[l1 ++];
else np[i] = p[l2 ++];
}
memcpy(p + l, np + l, sizeof (p[0]) * (r - l + 1));
}
bool cmp(const opt& a, const opt& b){
return a.k < b.k;
}
int main(){
scanf("%d", &n);
scanf("%lf", &f[0]);
for(int i = 1; i <= n; i ++){
scanf("%lf%lf%lf", &q[i].a, &q[i].b, &q[i].rate);
q[i].k = -q[i].a / q[i].b;
q[i].pos = i;
}
sort(q + 1, q + 1 + n, cmp);
solve(1, n);
printf("%.3lf\n", f[n]);
return 0;
}