题面
戳。
大意:一开始你只有一些钱.你可以用你的所有的钱去买a、b两种东西.你也可以用所有的a、b两种东西去换成钱.所以在一种情况下,你的手里只有钱或者a、b两种东西.
每一天a,b都有自己的价值,买入a,b时,都有一个固定的比值.也就是说,一定量的钱在某一天就对应了一定量的东西.
每一天的操作不限次数.
sol
如果你知道这是一道斜率优化dp,那么就很简单了.
列出式子发现,斜率式子中k不单调,x不单调,所以肯定有两个log。本蒟蒻会用树套树(各种splay,segment_tree,tree_array)等,然后CDQ分治.
但这不是重点。
重点是精度问题
说一下大致流程(CDQ)。
首先,为了保证你的决策范围是你之前的某一天,所以你永远只要考虑左边对右边的贡献.
进入CDQ分治中的一层,先去左半边区间,回溯到这一层的时候,你已经得到了左半边区间的一个保存凸包的数组(其实现在不一定是凸包,但这时横坐标是递增的),然后一个一个拿出来,由于横坐标递增,你只要一个一个放入斜率单调递减的单调队列,这时,单调队列里保存了一个横坐标递增,斜率递减的上凸包,然后把右半边的dp数组拿出来,在这个凸包上二分找最优决策点,然后递归进入右半边的区间,然后回溯到这一层,由于左右两边的横坐标都有序,所以再扫一遍,把有序的左右两边合成一个有序的整体,然后返回上一层
code
#include<bits/stdc++.h>
#define eps 1e-8
using namespace std;
const int _ = 100010;
const double INF = 20000000;
double f[_],g[_];
struct node{
double x,y;
}s[_],t[_];
int n,ss;
double A[_],B[_],Ra[_],MX;
double js(register node a,register node b){
return (b.y-a.y)/(b.x-a.x);
}
bool cmp(node a,node b){
return a.x-b.x<eps;
}
void CDQ(register int L,register int R){
if(L==R){
f[L]=max(f[L],f[L-1]);
g[L]=f[L]/(B[L]+Ra[L]*A[L]);
s[L].x=-g[L]*Ra[L];s[L].y=g[L];
return;
}
register int mid= (L+R)>>1;
CDQ(L,mid);
t[L]=s[L];
register int pin1=L,pin2=mid+1;
for(register int i=L+1;i<=mid;++i){
while((pin1>L&&eps<js(t[pin1],s[i])-js(t[pin1-1],s[i]) ) ){
if(t[pin1].x-s[i].x==0&&s[i].y<t[pin1].y)
break;
--pin1;
}
if(fabs(s[i].x-t[pin1].x) < eps)continue;
t[++pin1]=s[i];
}
for(register int i=mid+1;i<=R;++i){
register int l=L,r=pin1,mmid;
while(l<=r){
mmid= (l+r)>>1;
register double k1,k2,k3;
if(mmid==L)
k1=INF;
else k1=js(t[mmid-1],t[mmid]);
if(mmid==pin1)
k3=-INF;
else k3=js(t[mmid],t[mmid+1]);
k2=A[i]/B[i];
if(k2-k3>eps&&eps<k1-k2){
f[i]=max(f[i],t[mmid].y*B[i]-t[mmid].x*A[i]);
break;
}
if(eps<k3-k2)l=mmid+1;
else r=mmid-1;
}
}
CDQ(mid+1,R);
pin1=L;
register int ppl=L;
for(;pin1<=mid;++pin1){
while(pin2<=R&&eps<s[pin1].x-s[pin2].x)
t[ppl++]=s[pin2++];
t[ppl++]=s[pin1];
}
while(pin2<=R)t[ppl]=s[pin2],++pin2,++ppl;
for(register int i=L;i<=R;++i)
s[i]=t[i];
return;
}
int main(){
scanf("%d%d",&n,&ss);
for(register int i=1;i<=n;++i)scanf("%lf%lf%lf",&A[i],&B[i],&Ra[i]);
f[1]=ss;
CDQ(1,n);
printf("%.3lf\n",f[n]);
}