ws**
这里设(f_i)为前(i)天内得到的最多钱数,转移就考虑在第(i)天把钱变成券,然后枚举(>i)的(j),在第(j)天换成钱,这里要算出第(i)天换的B券数量,直接写转移(f_j=max(f_{j-1},max_{i<j} frac{f_i}{a_ir_i+b_i}(a_jr_i+b_j)))
考虑(frac{f_i}{a_ir_i+b_i}(a_jr_i+b_j) o f_j),先改成(frac{f_ir_i}{a_ir_i+b_i}*a_j+frac{f_i}{a_ir_i+b_i}*b_j o f_j),然后设(x_i=frac{f_ir_i}{a_ir_i+b_i},y_i=frac{f_i}{a_ir_i+b_i}),原式改写成(x_ia_j+y_ib_j o f_j)
然后把(y_i)提出,得(y_i=-frac{a_j}{b_j}x_i+frac{1}{b_j}f_j),所以(f_j)可以看做是对于点((x_i,y_i)),用斜率(k=-frac{a_j}{b_j})去经过这个点,得到的最大的截距的(/b_i)的值.所以如果把前面的所有((x_i,y_i))的上凸壳搞出来,那截距最大的((x_i,y_i))会满足在它前面的点之间的线段斜率(>-frac{a_j}{b_j}),后面的线段斜率(le-frac{a_j}{b_j})(可以画图理解),那么维护好凸壳后就可以每次(O(logn))转移了.由于凸壳一定是由一些横坐标不相同的点依次排列形成,所以可以搞一个以横坐标为关键字的平衡树,每次把新的点插到对应位置,然后用叉积删掉这个点的不合法前驱后继,使得凸包没有凹下去的地方
不想写平衡树可以写multiset,就是查询大概要两个log
#include<bits/stdc++.h>
#define LL long long
#define db double
using namespace std;
const int N=1e5+10;
const db eps=1e-10;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
return x*w;
}
db f[N];
struct node
{
db x,y;
bool operator < (const node &bb) const {return x<bb.x;}
node operator - (const node &bb) const {return (node){x-bb.x,y-bb.y};}
db operator * (const node &bb) const {return x*bb.y-bb.x*y;}
}nw;
db K(node aa,node bb){return (bb.y-aa.y)/(bb.x-aa.x);}
multiset<node> sb;
multiset<node>::iterator it,nt,n2;
int n;
int main()
{
///
n=rd(),f[1]=rd();
for(int i=1;i<=n;++i)
{
db a,b,c;
scanf("%lf%lf%lf",&a,&b,&c);
f[i]=max(f[i],f[i-1]);
if(!sb.empty())
{
it=sb.begin(),f[i]=max(f[i],((*it).y+(*it).x*a/b)*b);
it=--sb.end(),f[i]=max(f[i],((*it).y+(*it).x*a/b)*b);
db l=(*sb.begin()).x+eps,r=(*(--sb.end())).x-eps,ls=1e9;
while(r-l>eps&&r-l<ls)
{
ls=r-l;
db md=(l+r)/2;
it=sb.upper_bound((node){md,0});
if(it==sb.end()) break;
nt=--it,++it;
f[i]=max(f[i],max((*it).y+(*it).x*a/b,(*nt).y+(*nt).x*a/b)*b);
if(K(*it,*nt)>-a/b) l=(*it).x+eps;
else r=(*nt).x-eps;
}
}
nw=(node){f[i]/(a*c+b)*c,f[i]/(a*c+b)};
it=sb.insert(nw);
if(it!=sb.begin()&&it!=(--sb.end()))
{
nt=n2=it,--nt,++n2;
if(((*it)-(*nt))*((*n2)-(*it))>eps){sb.erase(it);continue;}
}
if(it!=sb.begin())
{
nt=it,--nt;
if(fabs((*it).x-(*nt).x)<eps)
{
if((*it).y<(*nt).y){sb.erase(it);continue;}
sb.erase(nt);
}
}
if(it!=(--sb.end()))
{
n2=it,++n2;
if(fabs((*it).x-(*n2).x)<eps)
{
if((*it).y<(*n2).y){sb.erase(it);continue;}
sb.erase(n2);
}
}
while(it!=sb.begin()&&it!=(++sb.begin()))
{
nt=it,--nt;
n2=nt,--n2;
if(((*nt)-(*it))*((*n2)-(*nt))>eps) break;
sb.erase(nt);
}
while(it!=(--sb.end())&&it!=(--(--sb.end())))
{
nt=it,++nt;
n2=nt,++n2;
if(((*nt)-(*it))*((*n2)-(*nt))<-eps) break;
sb.erase(nt);
}
}
printf("%.3lf
",f[n]);
return 0;
}