zoukankan      html  css  js  c++  java
  • BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包

    题意:链接

    方法:cdq分治或平衡树维护凸包

    解析:

    这道题我拒绝写平衡树的题解,我仅仅想说splay不要写挂,insert边界条件不要忘。del点的时候不要脑抽d错。有想写平衡树的去看140142或者留言我。

    首先这道题能推出个表达式

    f[i]代表第i天最大收益。

    xx[i]表示将第i天的钱都买A的数量

    yy[i]表示将第i天的钱都买B的数量

    所以f[i]=max(f[i1],p[i].axx[j]+p[i].byy[j])j<i

    所以我们要维护这个n^2的递推式

    又知道f[i]是由小于i的j更新的,

    但方程要进一步写一下

    yy[i]=(-p[i].a/p[i].b)*xx[i]+f[i]/p[i].b

    所以我们要得到最大截距所以能够依照斜率递减维护一个凸包来找某一确定直线与这个凸包截得的最大截距,也就是斜率第一个小于等于它的某个凸包上的点。

    之后的部分就是採用cdq维护或者平衡树

    平衡树真是一个噩梦

    代码:

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define N 100010
    #define eps 1e-9
    #define INF 0x7fffffff
    using namespace std;
    typedef long long ll;
    int n;
    double f[N];
    int stack[N];
    struct node
    {
        double x,y,a,b,rate,k;
        int w;
    }p[N],t[N];
    int cmp(node a,node b)
    {
        return a.k>b.k;
    }
    double getk(int a,int b)
    {
        if(!b)return -INF;
        if(fabs(p[a].x-p[b].x)<eps)return INF;
        return (p[b].y-p[a].y)/(p[b].x-p[a].x);
    }
    void solve(int l,int r)
    {
        if(l==r)
        {
            f[l]=max(f[l-1],f[l]);
            p[l].y=f[l]/(p[l].a*p[l].rate+p[l].b);
            p[l].x=p[l].rate*p[l].y;
            return;
        }
        int mid=(l+r)>>1;
        int l1=l,l2=mid+1,pt=1;
        for(int i=l;i<=r;i++)
        {
            if(p[i].w<=mid)t[l1++]=p[i];
            else t[l2++]=p[i];
        }
        for(int i=l;i<=r;i++)p[i]=t[i];
        solve(l,mid);
        int top=0;
        for(int i=l;i<=mid;i++)
        {
            while(top>1&&getk(stack[top-1],stack[top])<=getk(stack[top],i))top--;
            stack[++top]=i;
        }
        stack[++top]=0;
        for(int i=mid+1;i<=r;i++)
        {
            while(pt<top&&getk(stack[pt],stack[pt+1])>p[i].k)pt++;
            f[p[i].w]=max(f[p[i].w],p[stack[pt]].x*p[i].a+p[stack[pt]].y*p[i].b);
        }
        solve(mid+1,r);
        l1=l,l2=mid+1;
        for(int i=l;i<=r;i++)
           if(((p[l1].x<p[l2].x||(fabs(p[l1].x-p[l2].x)<eps&&p[l1].y<p[l2].y))||l2>r)&&l1<=mid)t[i]=p[l1++];
           else t[i]=p[l2++];
        for(int i=l;i<=r;i++)p[i]=t[i];
    } 
    int main()
    {
        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].w=i;
        }
        sort(p+1,p+1+n,cmp);
        solve(1,n);
        printf("%.3lf
    ",f[n]);
    }
  • 相关阅读:
    Notepad++ 使用nppexec插件配置简易开发环境
    Notepad++一键编译运行(Python、Java、C++)
    Java翁恺(1)——下载安装
    stm32正点原子学习笔记(30)窗口看门狗
    小程序模板
    Wireshark使用介绍(二):应用Wireshark观察基本网络协议
    Wireshark使用介绍(一):Wireshark基本用法
    Git 教程(四):标签和其他
    Git 教程(三):仓库与分支
    Git 教程(二):提交和回退
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/7119471.html
Copyright © 2011-2022 走看看