每一天的-a[i]/b[i]作为绿色的斜率k值,等价于求最右上的那条绿线与红线交点。维护一个凸包,将绿线一开始以k大小排序,这样一来就都具有单调性了,就可以使用斜率优化dp了
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define maxn 100020
#define eps 1e-9
#define LL long long
#include<algorithm>
using namespace std;
int n,s,sta[maxn];
double f[maxn];
struct node{
int id;
double a,b,x,y,k,r;
bool operator <(const node& bb)const{return k>bb.k;}
}p[maxn],q[maxn];
double getk(int a,int b){
if(!b)return -1e20;
if(fabs(p[a].x-p[b].x)<eps)return 1e20;
return (p[b].y-p[a].y)/(p[b].x-p[a].x);
}
void solve(int l,int r){
if(l==r){
f[l]=max(f[l],f[l-1]);
p[l].y=f[l]/(p[l].a*p[l].r+p[l].b);
p[l].x=p[l].y*p[l].r;
return;
}
int mid=l+r>>1,j=l,k=mid+1;
for(int i=l;i<=r;i++)
if(p[i].id<=mid)q[j++]=p[i];else q[k++]=p[i];
for(int i=l;i<=r;i++)p[i]=q[i];
solve(l,mid);
//跑凸包
k=0;
for(int i=l;i<=mid;i++){
while(k>1&&getk(sta[k],i)+eps>getk(sta[k-1],sta[k]))k--;
sta[++k]=i;
}sta[++k]=0,j=1;
for(int i=mid+1;i<=r;i++){
while(j<k&&getk(sta[j],sta[j+1])+eps>p[i].k)j++;
f[p[i].id]=max(f[p[i].id],p[sta[j]].x*p[i].a+p[sta[j]].y*p[i].b);
}
solve(mid+1,r);j=l,k=mid+1;
for(int i=l;i<=r;i++){
if(j<=mid&&((fabs(p[j].x-p[k].x)<eps&&p[j].y<p[k].y)||p[j].x<p[k].x||k>r))
q[i]=p[j++];
else q[i]=p[k++];
}
for(int i=l;i<=r;i++)p[i]=q[i];
}
int main(){
scanf("%d%lf",&n,f);
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].r);
p[i].k=-p[i].a/p[i].b;p[i].id=i;
}
sort(p+1,p+1+n);
solve(1,n);
printf("%.3lf",f[n]);
return 0;
}