60分做法:有提示得,每次必须买完或者卖完,感觉像dp
表示前天赚取的最多钱
其中 ,
#include<cstdio>
#include<iostream>
using namespace std;
const int N=1e5+5;
int n;
double f[N],a[N],b[N],r[N];
int main()
{
scanf("%d%lf",&n,&f[0]);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf",&a[i],&b[i],&r[i]);
for(int i=1;i<=n;i++)
{
f[i]=f[i-1];
for(int j=1;j<i;j++)
f[i]=max(f[i],(r[j]*a[i]+b[i])*f[j]/(a[j]*r[j]+b[j]));
}
printf("%.3lf\n",f[n]);
return 0;
}
100分做法:
这个式子很像斜率
所以就求截距最大(截距:一条直线与轴的交点的纵坐标)
维护一个上凸包
但无序,也无序,怎么办呢?
1、平衡树维护
2、cdq分治
菜鸡毫不犹豫选了cdq
#include<cmath>
#include<cstdio>
#include<iostream>
#define db double
using namespace std;
const int N=1e5+5;
const db eps=1e-7,INF=1e18;
int n,qu[N];
db f[N],a[N],b[N],r[N];
struct A{ int id; db k,x,y; } q[N],t[N];
inline db g(int i,int j)
{
if(abs(q[j].x-q[i].x)<eps) return q[i].y<q[j].y?INF:-INF;
return (q[i].y-q[j].y)/(q[i].x-q[j].x);
}
void work(int l,int r)
{
if(l==r)
{
f[l]=max(f[l],f[l-1]);
q[l].x*=f[l]; q[l].y*=f[l];
return;
}
int mid=l+r>>1;
work(l,mid);
int top=1; qu[1]=0;
for(int i=l;i<=mid;i++)
{
while(top>1&&g(qu[top-1],qu[top])<=g(qu[top-1],i)) top--;
qu[++top]=i;
}
for(int i=mid+1;i<=r;++i)
{
int L=2,R=top,s=1;
while(L<=R)
{
int M=L+R>>1;
if(g(qu[M-1],qu[M])>q[i].k) L=M+1,s=M;
else R=M-1;
}
f[i]=max(f[i],(-q[qu[s]].x*q[i].k+q[qu[s]].y)*b[i]);
}
work(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(q[i].x<=q[j].x) t[k++]=q[i++];
else t[k++]=q[j++];
}
while(i<=mid) t[k++]=q[i++];
while(j<=r) t[k++]=q[j++];
for(int i=l;i<=r;++i) q[i]=t[i];
}
int main()
{
scanf("%d%lf",&n,&f[0]);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf",&a[i],&b[i],&r[i]);
q[i]=(A){i,-a[i]/b[i],r[i]/(a[i]*r[i]+b[i]),(db)1/(a[i]*r[i]+b[i])}
}
work(1,n);
printf("%.3lf\n",f[n]);
return 0;
}