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.