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.

 

你可能感兴趣的:(ZOJ)