货币兑换
Solution
设 f(x) 表示第 x 天最多获得的金钱,则方程为:
移项,化简得到斜率公式:
a(i)b(i)[A(j)⋅r(j)−A(k)⋅r(k)]>[A(k)−A(j)]
其中 A(x)=f(x)/(aj⋅rj+bj) 。
可以用斜率优化,但因为 a(i)b(i) 、 A(i)⋅r(i) 均不单调,所以要用cdq分治
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define Max(x,y) ((x)>(y)?(x):(y))
#define eps (1e-8)
#define MAXN 100010
#define INF 1e+10
using namespace std;
struct Day{double a,b,r,x,y,A;int num;}day[MAXN],t[MAXN];
struct KKK{double ks;int num;}stack[MAXN];
double f[MAXN];
int n,s,Max_Right,limit=sizeof(Day),Lastcost;
inline int compare(double x){
if(fabs(x)<=eps)return 0;
return x>0?1:-1;
}
bool cmp(Day x,Day y){
if(fabs(x.a/x.b-y.a/y.b)<=eps||x.a/x.b-y.a/y.b<0)return true;
return false;
}
double get_k(int x,int y){
if(day[x].x==day[y].x)return INF;
return (day[x].y-day[y].y)/(day[x].x-day[y].x);
}
void solve(int l,int r){
if(l==r){
f[day[l].num]=Max(f[day[l].num],f[day[l].num-1]);
day[l].A=f[day[l].num]/(day[l].a*day[l].r+day[l].b);
day[l].x=day[l].A*day[l].r,day[l].y=-day[l].A;
}
else{
int mid=(l+r)>>1,fir=l,sec=mid+1;
for(int i=l;i<=r;i++){
if(day[i].num<=mid)t[fir++]=day[i];
else t[sec++]=day[i];
}
for(int i=l;i<=r;i++)day[i]=t[i];
solve(l,mid);Max_Right=Lastcost=1;
stack[Max_Right].num=l;stack[Max_Right].ks=-INF;
for(int i=l+1;i<=mid;i++){
while(compare(get_k(stack[Max_Right].num,i)-stack[Max_Right].ks)<=0)Max_Right--;
stack[++Max_Right].num=i;stack[Max_Right].ks=get_k(stack[Max_Right-1].num,i);
}
stack[Max_Right+1].ks=INF;
for(int i=mid+1;i<=r;i++){
double tmp=day[i].a/day[i].b;
while((compare(stack[Lastcost].ks-tmp)>0||compare(stack[Lastcost+1].ks-tmp)<0)&&Lastcost<Max_Right)Lastcost++;
int pos=day[stack[Lastcost].num].num,real=day[i].num;
f[real]=Max(f[real],f[pos]*(day[stack[Lastcost].num].r*day[i].a+day[i].b)/(day[stack[Lastcost].num].a*day[stack[Lastcost].num].r+day[stack[Lastcost].num].b));
}
solve(mid+1,r);
fir=l,sec=mid+1;
for(int i=l;i<=r;i++){
if(fir>mid)t[i]=day[sec++];
else if(sec>r)t[i]=day[fir++];
else{
double tx=day[fir].x,ty=day[sec].x;
if(compare(tx-ty)<=0)t[i]=day[fir++];
else t[i]=day[sec++];
}
}
for(int i=l;i<=r;i++)day[i]=t[i];
}
}
int main(){
freopen("cash.in","r",stdin);
freopen("cash.out","w",stdout);
scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&day[i].a,&day[i].b,&day[i].r),day[i].num=i;
sort(day+1,day+n+1,cmp);
f[1]=s;solve(1,n);
printf("%.3lf",f[n]);
return 0;
}