• [bzoj 1492][NOI2007]货币兑换Cash


    传送门

    Solution

    一道很早以前做过的题,突然想补篇博客……

    方程什么的就不展现了。

    反正斜率优化的题都挺好写的。

    斜率优化的核心是:

    [frac{Y_j-Y_k}{X_j-X_k}leq W_i ]

    可以把每个决策(j)用两个数(X_j),(Y_j)来表示,然后如果(X_j)是个单增的呢,直接用单调栈就能维护凸壳(因为求凸壳的时候就要(x-y)排序一波啊),其实,我们不如说是在维护一个斜率的单调队列,所以如果(W_i)和斜率的单调性相同,就可以直接用单调队列找决策点啦。

    (W_i)没有单调性的话,就只能二分找决策点了。

    比较头疼的是要是(X_i)没有单调性的话,我们就需要维护一个可以在中间加点的凸壳,平衡树即可。

    而cdq分治的思想就是分治区间,只考虑前面的决策对后面的询问的影响,而顺序是不需要考虑的,所以直接对前面的决策(x-y)排序求凸壳,对后面的询问按照(W_i)排序,这样一来,就又可以直接用单调队列找决策点啦。


    Code 

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    #define inf 0x7fffffff
    #define MN 120000
    #define sign(a) (((a)>-eps)-((a)<eps))
    #define eps 1e-8
    int n;
    struct day{double A,B,rate;}a[MN];
    double ans[MN],f[MN],g[MN];
    int hd,tl,q[MN],krk[MN],rk[MN];
    inline bool cmp(int x,int y){
        return f[x]<f[y]||(sign(f[x]-f[y])==0&&g[x]<g[y]);
    }
    inline double calc(int x,int y){
        if(sign(f[x]-f[y])==0) return (g[x]-g[y])*inf;
        return (g[x]-g[y])/(f[x]-f[y]);
    }
    inline bool cmpk(int x,int y){
        return sign((-a[x].A/a[x].B)-(-a[y].A/a[y].B))>0;
    }
    void solve_cdq(int l,int r){
        if(l==r){g[l]=f[l]/a[l].rate;return;}
        register int i,mid=(l+r)>>1;
        solve_cdq(l,mid);
        for(i=mid+1;i<=r;i++) rk[i]=i;sort(rk+l,rk+mid+1,cmp);
        for(i=mid+1;i<=r;i++) krk[i]=i;sort(krk+mid+1,krk+r+1,cmpk);
        tl=0,hd=1;
        for(i=l;i<=mid;i++){while(tl>1&&calc(q[tl-1],q[tl])<calc(q[tl],rk[i])) --tl;q[++tl]=rk[i];}
        for(i=mid+1;i<=r;i++){
            while(hd<tl&&sign(calc(q[hd],q[hd+1])-(-a[krk[i]].A/a[krk[i]].B))>=0)++hd;
            ans[krk[i]]=max(ans[krk[i]],f[q[hd]]*a[krk[i]].A+g[q[hd]]*a[krk[i]].B);
        }
        for(i=mid+1;i<=r;++i)
            ans[i]=max(ans[i],ans[i-1]),f[i]=ans[i]*a[i].rate/(a[i].A*a[i].rate+a[i].B);
        solve_cdq(mid+1,r);
    }
    int main(){
        register int i;
        n=read();scanf("%lf",&ans[1]);
        for(i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i].A,&a[i].B,&a[i].rate),rk[i]=i;
        f[1]=ans[1]*a[1].rate/(a[1].A*a[1].rate+a[1].B);
        solve_cdq(1,n);
        printf("%.3f
    ",ans[n]);
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    CAD迷你看图
    CAD打开文件总是弹出要求选择字体怎么办
    CAD字体显示问号的解决办法
    如何让IE8的菜单栏调到最上方
    苹果公司在 1980 年上市时为什么不使用双层股权架构来确保乔布斯有着足够的控制权?
    怪不的软件开发这么挣钱,原来是有这么多职位
    剖析余额宝“好”与“坏”
    网上盗刷事件频发 风险肇始于“快捷支付”?
    招商银行网银专业版怎么消除安全隐患
    《浅谈磁盘控制器驱动》,磁盘控制器驱动答疑解惑![2012.1.29完结]by skyfree
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10241783.html
Copyright © 2020-2023  润新知