• bzoj1492: [NOI2007]货币兑换Cash


    cdq分治,dp。这道题太难了,我看了一上午一点头绪也没有//蒟蒻本性

    连这篇题解都是边做边写的,要不就忘了(雾)。。

    维护的是上凸包。

    2.30 pm 终于过了,照着人家的题解打,居然都交了10多遍。//蒟蒻本性

    首先,不难得到这样的结论:如果买就要把所有的钱都用完(买能挣钱,就要多买,不如其他的挣钱就买别的)。如果卖,就要都卖掉。

    用数组a保存a[i],b[i],rate[i]。

    用f[i].x代表第x天能买到最多的a物品,f[i].y代表最多的b物品。则有f[i].x = f[i].y*a[i].r。

    用v[i]代表第i天能得到最大的收益,则有v[i] = max(v[i]-1,f[i].x*a[i]+f[i].y*b[i])。

    暴力枚举O(n^2),tle。

    所以需要维护一个上凸包。

    在第i天时,假设f[j].x<=f[k].x,如果决策j优于k,则有 (f[i].x-f[j].x)*a[i].a+(f[j].y-f[k].y)*a[i].b>0。

    经过移项,就有 (f[j].y-f[j].y)/(f[j].x-f[j].x) < –a[i].a/a[i].b。

    先记住这个结论,那么利用呢?

    1.在预处理时先按(-a[i]/b[i])降序排序。

    2/然后依靠平衡树(我不会。。)和cdq分治(我抄的。。)了。

    cdq分治:首先先把要处理的区间分成俩部分,先递归处理左区间,然后计算右区间,最后递归处理右区间。

    这样有什么好处呢? 就是在计算一天的dp值的时候,也处理了后面所有天数的dp值的一部分。

    为什么呢?如果我们按单调性排序了以后,维护出一个下凸包。

    在处理第j天时,假设第k天为决策最优,这样k天以前的值在第j天以后的决策中都没用了。

    因为满足 小于 –a[j].a/a[j].b,必定小于–a[h].a/a[h].b,h>j。因为排序过了。

    分治一共logn层,每层遍历n个数,总复杂度O(nlogn)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int maxn = 100000 + 10;
    
    int n,m,p[maxn],s[maxn];
    struct Point {
        double x,y;
    }f[maxn],t[maxn];
    struct DAY {
        double a,b,r;
    } a[maxn];
    double v[maxn];
    
    bool operator < (Point a,Point b) {
        return a.x < b.x || (a.x==b.x&&a.y<b.y);
    }
    
    bool cmp(int x,int y) {
        return a[x].b/a[x].a > a[y].b/a[y].a;
    }
    
    bool dir(Point a,Point b,Point c) {
        return ((b.x-a.x)*(c.y-b.y)-(b.y-a.y)*(c.x-b.x))>=0;
    }
    
    double calc(Point f,int i) {
        return f.x*a[i].a + f.y*a[i].b;
    }
    
    void cdq(int l,int r,double m) {
        if(l == r) {
            v[l] = max(v[l],m);
            f[l].y = v[l]/(a[l].a*a[l].r+a[l].b);
            f[l].x = a[l].r*f[l].y;
            return;
        }
        
        int mid = (l+r)/2,m1=l,m2=mid+1,L=0,R=0;
        for(int i=l;i<=r;i++) {
            if(p[i]<=mid) s[m1++]=p[i];
            else s[m2++]=p[i];
        }
        memcpy(p+l,s+l,sizeof(int)*(r-l+1)); 
        cdq(l,mid,m);
        for(int i=l;i<=mid;i++) {
            while(R>1 && dir(t[R-2],t[R-1],f[i])) R--;
            t[R++] = f[i]; 
        }
        
        for(int i=mid+1;i<=r;i++) {
            while(L<R-1 && calc(t[L],p[i])<calc(t[L+1],p[i])) ++L;
            v[p[i]] = max(v[p[i]],calc(t[L],p[i]));
        }
        cdq(mid+1,r,v[mid]);
        
        merge(f+l,f+mid+1,f+mid+1,f+r+1,t);
        memcpy(f+l,t,sizeof(Point)*(r-l+1));
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) {
            scanf("%lf%lf%lf",&a[i].a,&a[i].b,&a[i].r);
            p[i] = i;
        }
        sort(p+1,p+n+1,cmp);
        cdq(1,n,m);
        printf("%.3lf
    ",v[n]);
        return 0;
    }

     

  • 相关阅读:
    PHP操作MYSQL数据库
    微信DLL劫持反弹shell复现
    ERROR Invalid options in vue.config.js: "baseUrl" is not allowed
    求曲线y=lnx在区间(2,6)内的一条切线,使得该切线与直线x=2,x=6及曲线y=lnx所围成的图形的面积最小。
    CentOS、Ubuntu、Debian三个linux比较异同
    jpa模糊查询(表中的某些数据)
    jpa查找数据库最新一条消息
    在@Data注释lombok上使用继承警告等于/ hashCode(Warning equals/hashCode on @Data annotation lombok with inheritance)
    git基本操作
    远程分支git换地址了,本地重新关联
  • 原文地址:https://www.cnblogs.com/invoid/p/5398401.html
Copyright © 2020-2023  润新知