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.

 

posted on 2014-01-14 17:16  BLADEVIL  阅读(311)  评论(0编辑  收藏  举报