货币兑换【题解】

题面


大意:一开始你只有一些钱.你可以用你的所有的钱去买a、b两种东西.你也可以用所有的a、b两种东西去换成钱.所以在一种情况下,你的手里只有钱或者a、b两种东西.
每一天a,b都有自己的价值,买入a,b时,都有一个固定的比值.也就是说,一定量的钱在某一天就对应了一定量的东西.
每一天的操作不限次数.

sol

如果你知道这是一道斜率优化dp,那么就很简单了.
列出式子发现,斜率式子中k不单调,x不单调,所以肯定有两个log。本蒟蒻会用树套树(各种splay,segment_tree,tree_array)等,然后点分治.
但这不是重点。
重点精度

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]);
}

猜你喜欢

转载自blog.csdn.net/JH_2002/article/details/81512139