考虑令
f
[
i
]
f[i]
f[i]为第
i
i
i天得到的最多的
A
A
A券,
g
[
i
]
g[i]
g[i]为第
i
i
i天得到的最多的
B
B
B券
则
g
[
i
]
=
f
[
i
]
/
r
a
t
e
[
i
]
g[i]=f[i]/rate[i]
g[i]=f[i]/rate[i]
那显然有个
n
2
d
p
n^2dp
n2dp,暴力枚举前一天转移
但显然这样得不到满分
考虑如果前面
i
,
j
i,j
i,j两天对于决策
n
o
w
now
now的影响,如果
i
i
i比
j
j
j优的话
则
(
f
[
i
]
−
f
[
j
]
)
∗
a
[
n
o
w
]
−
(
g
[
i
]
−
g
[
j
]
)
∗
b
[
n
o
w
]
>
0
(f[i]-f[j])*a[now]-(g[i]-g[j])*b[now]>0
(f[i]−f[j])∗a[now]−(g[i]−g[j])∗b[now]>0
即 g [ i ] − g [ j ] f [ i ] − f [ j ] < − a [ n o w ] b [ n o w ] \frac{g[i]-g[j]}{f[i]-f[j]}<-\frac{a[now]}{b[now]} f[i]−f[j]g[i]−g[j]<−b[now]a[now]
注意特判一个 f [ i ] = f [ j ] f[i]=f[j] f[i]=f[j]的情况
如果将 ( f [ i ] , g [ i ] ) (f[i],g[i]) (f[i],g[i])作为平面上的点,那也就是我们维护一个上凸壳
则对于每一个 n o w now now,我们找到最后一个满足相邻2点斜率小于 − a [ n o w ] b [ n o w ] -\frac{a[now]}{b[now]} −b[now]a[now]的点,并把这个点更新当前节点的答案
但我们发现这个无法二分求
考虑splay动态维护
c
d
q
cdq
cdq分治维护凸包
具体的我们可以使
n
o
w
now
now保持有序
就可以一边扫凸包一边更新了
可以大力
s
o
r
t
sort
sort,不过要多一个
l
o
g
log
log
也可以
c
d
q
cdq
cdq分治中途把凸包和
−
a
[
n
o
w
]
b
[
n
o
w
]
-\frac{a[now]}{b[now]}
−b[now]a[now]顺带归并排序
复杂度 O ( n l o g n ) O(nlogn) O(nlogn),似乎不比每次 s o r t sort sort快多少……
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res*f;
}
#define db double
const double eps=1e-8;
#define inf 0x7fffffff
const int N=100005;
int n,top,stk[N],id[N],tmp[N],idx[N],tmpk[N],bel[N];
db ans[N],f[N],g[N],ak[N],bk[N],rate[N];
inline db max(db a,db b){return a>b?a:b;}
inline int check(db k){
return (k>-eps)-(k<eps);
}
inline bool comp(int a,int b){
return f[a]<f[b]||(check(f[a]-f[b])==0&&g[a]<g[b]);
}
inline double k(int a,int b){
if(check(f[a]-f[b])==0)return check(g[a]-g[b])*inf;
return ((g[a]-g[b])/(f[a]-f[b]));
}
inline bool compk(int a,int b){
return check((-ak[a]/bk[a])-(-ak[b]/bk[b]))>0;
}
void cdq(int l,int r){
if(l==r){g[l]=f[l]/rate[l];return;}
int mid=(l+r)>>1,cnt1=l-1,cnt2=mid,cnt=l-1;
for(int i=l;i<=r;i++)
if(bel[idx[i]]<=mid)tmpk[++cnt1]=idx[i];
else tmpk[++cnt2]=idx[i];
for(int i=l;i<=r;i++)idx[i]=tmpk[i];
cdq(l,mid);top=0;
for(int i=l;i<=mid;i++){
while(top>=2&&k(stk[top-1],stk[top])<k(stk[top],id[i]))top--;
stk[++top]=id[i];
}
for(int now=1,i=mid+1;i<=r;i++){
int t=bel[idx[i]];
while(now<top&&check(k(stk[now],stk[now+1])-(-ak[t]/bk[t]))>=0)now++;
ans[t]=max(ans[t],f[stk[now]]*ak[t]+g[stk[now]]*bk[t]);
}
for(int i=mid+1;i<=r;i++){
int t=bel[idx[i]];ans[t]=max(ans[t],ans[t-1]),f[t]=ans[t]*rate[t]/(ak[t]*rate[t]+bk[t]);
}
cdq(mid+1,r);
cnt1=l,cnt2=mid+1,cnt=l;
while(cnt1<=mid&&cnt2<=r)
if(comp(id[cnt1],id[cnt2]))tmp[cnt++]=id[cnt1++];
else tmp[cnt++]=id[cnt2++];
while(cnt1<=mid)tmp[cnt++]=id[cnt1++];
while(cnt2<=r)tmp[cnt++]=id[cnt2++];
for(int i=l;i<=r;++i)id[i]=tmp[i];
}
int main(){
n=read();scanf("%lf",&ans[1]);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf",&ak[i],&bk[i],&rate[i]);
f[1]=ans[1]*rate[1]/(ak[1]*rate[1]+bk[1]);
for(int i=1;i<=n;i++)id[i]=idx[i]=bel[i]=i;
sort(bel+1,bel+n+1,compk);
cdq(1,n);
printf("%.3lf",ans[n]);
}