题意
分析
设 f i f_i fi表示第i天卖出手中所有的券后的最大金额
贪心的考虑,如果有买卖操作一定是将所有的金额全部花完更优
第 i 天可以不经过卖的操作
f
i
=
f
i
−
1
f_i=f_{i-1}
fi=fi−1
如果第 i 天卖了第 j 天买的
f
i
=
a
i
x
j
+
b
i
y
j
f_i=a_ix_j+b_iy_j
fi=aixj+biyj
其中
x
j
,
y
j
x_j,y_j
xj,yj分别表示第 j 天按照比例购买的AB券数量
y j = − a i b i x + f i b i y_j=-\frac{a_i}{b_i}x+\frac{f_i}{b_i} yj=−biaix+bifi,这样就是要最大化截距,但 x x x和 k k k都不单调
可以使用cdq分治来解决,先把所有点按照斜率从大到小排序
分治过程先递归处理左区间,然后归并把左侧区间按照 x x x排序,右侧区间按照 k k k的顺序,这样就可以直接建立凸包,单调队列就计算左区间对右区间的贡献,最后再递归处理右区间
细节:注意递归到 l = r l=r l=r的时候,要先更新 f i = f i − 1 f_i=f_{i-1} fi=fi−1,同时 x , y x,y x,y也需要在return前计算
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const double eps=1e-10;
int n;
struct point
{
double a,b,x,y,rate,k;
int id;
}p[maxn],tmp[maxn];
double f[maxn];
bool cmp(point x,point y)
{
return x.k>y.k;
}
int st[maxn];
double calc_k(int i,int j)
{
if(fabs(p[j].x-p[i].x)<eps) return 1e18;
return (p[j].y-p[i].y)/(p[j].x-p[i].x);
}
void cdq(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].rate+p[l].b);
p[l].x=p[l].y*p[l].rate;
return;
}
int mid=l+r>>1;
int tmpl=l-1,tmpr=mid;
for(int i=l;i<=r;i++)
{
if(p[i].id<=mid) tmp[++tmpl]=p[i];
else tmp[++tmpr]=p[i];
}
for(int i=l;i<=r;i++) p[i]=tmp[i];
cdq(l,mid);
int head=1,tail=0;
for(int i=l;i<=mid;i++)
{
while(head<=tail && calc_k(st[tail-1],st[tail])<calc_k(st[tail-1],i)+eps)
tail--;
st[++tail]=i;
}
for(int i=mid+1;i<=r;i++)
{
while(head<tail && calc_k(st[head],st[head+1])+eps>p[i].k)
head++;
f[p[i].id]=max(f[p[i].id],p[st[head]].x*p[i].a+p[st[head]].y*p[i].b);
}
cdq(mid+1,r);
tmpl=l; tmpr=mid+1;
int now=l-1;
while(tmpl<=mid && tmpr<=r)
{
if(p[tmpl].x<p[tmpr].x) tmp[++now]=p[tmpl++];
else tmp[++now]=p[tmpr++];
}
for(int i=tmpl;i<=mid;i++) tmp[++now]=p[i];
for(int i=tmpr;i<=r;i++) tmp[++now]=p[i];
for(int i=l;i<=r;i++) p[i]=tmp[i];
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d%lf",&n,&f[0]);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].rate);
p[i].k=-p[i].a/p[i].b;
p[i].id=i;
}
sort(p+1,p+n+1,cmp);
cdq(1,n);
printf("%.3f\n",f[n]);
return 0;
}