zoukankan      html  css  js  c++  java
  • bzoj 1942 斜率优化DP

      首先我们贪心的考虑,对于某一天来说,我们只有3中策略,第一种为不做任何行动,这时的答案与前一天相同,第二种为将自己的钱全部换成a,b货币,因为如果换a,b货币,代表在之后的某一天卖出去后会赚钱,那么当时手中的a,b货币越多,盈利越多,所以全买。第三种策略为将自己的货币全部卖出,贪心正确性和第二种类似。

      那么我们设w[i]为到第i天,手中最多有多少钱,那么就可以比较容易的列出转移方程w[i]=max(w[i-1],第j天将所有的货币卖出,第i天卖掉的钱),这样的时间复杂度为n^2,显然不能通过全部测试数据,那么我们考虑优化。

      w[i-1]比较容易考虑,那么我们现在要求的就是对于固定的i,第j天将所有的货币卖出,第i天卖掉的钱的最大值,设这个为tot,那么我们用式子表示出这个来,因为第j天剩下w[j]的钱,那么我们可以换成a货币w[j]/(a[j]+b[j]*rate[j]),b货币为rate[j]*a货币,那么设x[i]为第i天的钱全部换成a货币的数量,y[i]为第i天的钱全部换成b货币的数量,那么则有x[i]=w[i]/(a[i]+b[i]*rate[i]),y[i]=x[i]*rate[i],那么第j天的货币在第i天卖掉获得的钱为a[i]*x[j]+b[i]+y[j],那么w[i]=max(w[i-1],a[i]*x[j]+b[i]*y[j]),现在我们求的就是z=a[i]*x[j]+b[i]*y[j]的最大值,那么用线性规划的方法,y[j]=z/b[i]-x[j]*a[i]/b[i],显然当使斜率为-a[i]/b[i]的直线的纵截距最大的时候答案最优,那么我们只需要维护一个x,y坐标的下凸壳即可。

      但是这道题的x坐标显然没有什么单调性,所以我们可以用splay来维护。

    /**************************************************************
        Problem: 1492
        User: BLADEVIL
        Language: Pascal
        Result: Accepted
        Time:1540 ms
        Memory:10192 kb
    ****************************************************************/
     
    //By BLADEVIL
    const
        eps                     =1e-9;
         
    var
        n                       :longint;
        w, a, b, rate           :array[0..100010] of extended;
        x, y                    :array[0..100010] of extended;
        lk, rk                  :array[0..100010] of extended;
        root                    :longint;
        son                     :array[0..100010,0..1] of longint;
        father                  :array[0..100010] of longint;
         
    function max(a,b:extended):extended;
    begin
        if a>b then exit(a) else exit(b);
    end;    
     
    procedure init;
    var
        i                       :longint;
    begin
        read(n,w[0]);
        for i:=1 to n do read(a[i],b[i],rate[i]);
    end;
     
    function fabs(x:extended):extended;
    begin
        if x>0 then exit(x) else exit(-x);
    end;
     
    procedure rotate(x:longint;var root:longint);
    var
        y, z, p, q              :longint;
    begin
        y:=father[x];
        z:=father[y];
        if son[y][1]=x then p:=1 else p:=0;
        q:=p xor 1;
        if y=root then root:=x 
            else if son[z][0]=y then
                son[z][0]:=x else son[z][1]:=x;
        father[x]:=z; father[y]:=x; 
        father[son[x][q]]:=y;
        son[y][p]:=son[x][q];
        son[x][q]:=y;
    end;
     
    procedure splay(x:longint;var root:longint);
    var
        y, z                    :longint;
    begin
        while x<>root do
        begin
            y:=father[x];
            z:=father[y];
            if y<>root then
                if (son[y][0]=x) xor (son[z][0]=y)
                then rotate(x,root) else rotate(y,root);
            rotate(x,root);
        end;
    end;
     
    procedure insert(var t:longint;anc,now:longint);
    begin
        if t=0 then
        begin
            t:=now;
            father[t]:=anc;
            exit;
        end;
        if (x[now]<=x[t]+eps) then
            insert(son[t][0],t,now) else
            insert(son[t][1],t,now);
    end;
     
    function getk(i,j:longint):extended;
    begin
        if fabs(x[i]-x[j])<eps then exit(-maxlongint);
        exit((y[j]-y[i])/(x[j]-x[i]));
    end;
     
    function prev(root:longint):longint;
    var
        rot, tmp                :longint;
    begin
        rot:=son[root][0];
        tmp:=rot;
        while rot<>0 do
        begin
            if (getk(rot,root)<=lk[rot]+eps) then
            begin
                tmp:=rot;
                rot:=son[rot][1];
            end else rot:=son[rot][0];
        end;
        exit(tmp);
    end;
     
    function succ(root:longint):longint;
    var
        rot, tmp                :longint;
    begin
        rot:=son[root][1];
        tmp:=rot;
        while rot<>0 do
        begin
            if (getk(root,rot)+eps>=rk[rot]) then
            begin
                tmp:=rot;
                rot:=son[rot][0];
            end else rot:=son[rot][1];
        end;
        exit(tmp);
    end;
     
    procedure update(t:longint);
    var
        left, right             :longint;
    begin
        splay(t,root);
        if son[t][0]<>0 then
        begin
            left:=prev(root);
            splay(left,son[root][0]);
            son[left][1]:=0;
            lk[t]:=getk(left,t);
            rk[left]:=lk[t];
        end else lk[t]:=maxlongint;
        if son[t][1]<>0 then
        begin
            right:=succ(root);
            splay(right,son[root][1]);
            son[right][0]:=0;
            rk[t]:=getk(t,right);
            lk[right]:=rk[t];
        end else rk[t]:=-maxlongint;
        if (lk[t]<=rk[t]+eps) then
        begin
            root:=son[t][0];
            son[root][1]:=son[t][1];
            father[son[t][1]]:=root;
            father[root]:=0;
            rk[root]:=getk(root,son[t][1]);
            lk[son[t][1]]:=lk[root];
        end;
    end;
     
    function find(t:longint;k:extended):longint;
    begin
        if t=0 then exit(0);
        if (lk[t]+eps>=k) and (k+eps>=rk[t]) then exit(t);
        if (k+eps>lk[t]) then
            exit(find(son[t][0],k)) else
            exit(find(son[t][1],k));
    end;
     
    procedure main;
    var
        i                       :longint;
        p                       :longint;
    begin
        for i:=1 to n do
        begin
            p:=find(root,-a[i]/b[i]);
            w[i]:=max(w[i-1],x[p]*a[i]+y[p]*b[i]);
            y[i]:=w[i]/(a[i]*rate[i]+b[i]);
            x[i]:=y[i]*rate[i];
            insert(root,0,i);
            update(i);
        end;
        writeln(w[n]:0:3);
    end;
     
    begin
        init;
        main;
    end.
  • 相关阅读:
    Eclipse Kepler安装WST Server Adapter后创建Server无Tomcat解决方法
    centos下Linux C语言MD5的使用
    解析JSON字符串
    切换view的动画
    设置菜单和工具条
    视图切换的几种方法
    scrollview 例子2
    UIScrollView
    iOS:翻页效果
    软件预构的艺术源码编译
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3519440.html
Copyright © 2011-2022 走看看