写着题写的想死。。。来扯扯写着题的过程。。。(我菜啊)
早晨总结了一下昨天写的几道决策单调性和斜率优化dp,然后突然看到这题,准备来写,此时8:30。
看了popoQQQ的题解,感觉这题代码有点难度,不过还是要挑战一下的,然后大概理了理思路和细节,就开始码了,此时9:00。
10:40码完,调了几个splayRE的地方,11:00过了样例(样例很水啊),交一发,TLE(后来分析应该是死循环了)。。。
瞎搞了一下没什么结果,于是把popoQQQ的std搬了下来,又手写了个暴力输出决策点,开拍,12:00之前拍出三个WA点,吃完饭发现又拍出错来了,于是回去睡午觉。
下午14:00又开始拍,发现了一个致命的错误,应该把根节点s与点p斜率和p与p的前驱(or后继)的斜率比较,我把s和s的前驱(or后继)直接拿去比了,这时15:00。
然后发现拍大一点都可以过,但是小数据如果两个点横坐标相同,求斜率会挂掉(popoQQQ的std好像挂了?),于是求斜率的地方写了个特判,拍了几十秒没挂,交一发500msWA,此时15:40。
把特判去掉,果真RE。然后又发现横坐标相同splay中顺序又有可能会挂,于是又在splay里写了个特判,这回拍了好久都没挂了,此时16:00。
自信交一发,0msWA!!!气啊,于是开始颓了。。。颓到16:50,想起同学们都还在物理周练,又不好意思在颓了,问bzoj的admin要了一发数据,
一测,AC了!!!
满怀着好奇又交了一发,竟然OJ上也A了,看一眼之前0msWA的程序,没有删文件输入输出,BZOJ竟然报WA不报RE,妈的。。。于是一天就毁在一题上。。。
题解:HINT里面都说了,买进就要全买进,卖出就要全卖出,于是dp方程就很好想了,f[i]表示第i天卖出所有AB券总共能获得的钱,于是dp[i]=max{a[i] *x[j]+b[i] *y[j]} (1<=j<=i-1) ,a[],b[]表示当天标价,x[],y[]表示把那天的钱分别能换成多少AB券,其实这里枚举的j就是那天买进。引用popoQQQ的一句话“万事具备,只是AB不单调”。。。于是必须要用splay来维护决策的凸壳。
我是这样实现的,按X坐标顺序建splay,每个点记两个斜率qk和hk表示这个点和前一个点/后一个点的斜率(第一个点qk=0,最后一个点hk=-INF)。插入一个点的时候,先把它扔进splay里旋到根s,然后在它左子树中找p.qk>k(p,s)的最小的p点,旋到左子树根,删除它的右子树,若找不到大于的,整个左子树都应该删掉。右子树同理。找最优决策点的时候(加入查找斜率为k),应该在splay中找那个qk>=k>=hk的点。
听说还有CDQ分治做法。
代码:
这种题pascal狗能200行左右已经不错了。。。
type
tree=^treenode;
treenode=record
x,y,qk,hk:double;
l,r,f:tree;
end;
const maxl=1000000000;
eps=0.0000000001;
var
n,i,j,size:longint;
s,f:double;
a,b,r,x,y:array[0..100100]of double;
str,dc:tree;
function max(x,y:double):double;
begin
if x>y then exit(x)
else exit(y);
end;
function calk(x,y:tree):double;
begin
if abs(x^.x-y^.x)<eps then
begin
if (x^.y-y^.y)*(x^.x-y^.x)>0 then exit(maxl)
else exit(-maxl);
end;
exit((x^.y-y^.y)/(x^.x-y^.x));
end;
procedure left(x:tree);
begin
x^.f^.r:=x^.l;
if x^.l<>nil then x^.l^.f:=x^.f;
x^.l:=x^.f;
x^.f:=x^.l^.f;
x^.l^.f:=x;
if x^.f<>nil then
begin
if x^.f^.l=x^.l then x^.f^.l:=x
else x^.f^.r:=x;
end;
end;
procedure right(x:tree);
begin
x^.f^.l:=x^.r;
if x^.r<>nil then x^.r^.f:=x^.f;
x^.r:=x^.f;
x^.f:=x^.r^.f;
x^.r^.f:=x;
if x^.f<>nil then
begin
if x^.f^.l=x^.r then x^.f^.l:=x
else x^.f^.r:=x;
end;
end;
procedure splay(var s:tree;x:tree);
var
p,sf:tree;
begin
sf:=s^.f;
while x^.f<>sf do
begin
p:=x^.f;
if p^.f=sf then
begin
if p^.l=x then right(x)
else left(x);
end
else
begin
if p^.f^.l=p then
begin
if p^.l=x then right(p)
else left(x);
right(x);
end
else
begin
if p^.r=x then left(p)
else right(x);
left(x);
end;
end;
end;
s:=x;
end;
procedure ins(var s:tree;x,y:double);
var
p,last,qz,hz:tree;
begin
if s=nil then
begin
new(s);
s^.x:=x;s^.y:=y;s^.qk:=0;s^.hk:=-maxl;
s^.l:=nil;s^.r:=nil;s^.f:=nil;
exit;
end;
p:=s;
while p<>nil do
begin
last:=p;
if (x<p^.x)or((abs(x-p^.x)<eps)and(y>p^.y)) then p:=p^.l
else p:=p^.r;
end;
new(p);
p^.x:=x;
p^.y:=y;
p^.qk:=0; p^.hk:=-maxl;
p^.l:=nil; p^.r:=nil;
if (x<last^.x)or((abs(x-last^.x)<eps)and(y>last^.y)) then last^.l:=p
else last^.r:=p;
p^.f:=last;
splay(s,p);
end;
procedure inspoint(var s:tree;x,y:double);
var
p,q,last:tree;
begin
ins(s,x,y);
last:=s;
p:=s^.l;
while p<>nil do
begin
if (abs(s^.x-p^.x)>eps)and(calk(s,p)+eps<p^.qk) then begin last:=p; p:=p^.r end
else p:=p^.l;
end;
if s^.l<>nil then
begin
if last=s then
begin
s^.l^.f:=nil;
s^.l:=nil;
s^.qk:=0
end
else
begin
splay(s^.l,last);
if last^.r<>nil then last^.r^.f:=nil;
last^.r:=nil;
s^.qk:=calk(s,last);
last^.hk:=s^.qk;
end;
end;
last:=s;
p:=s^.r;
while p<>nil do
begin
if (abs(s^.x-p^.x)>eps)and(calk(s,p)+eps>p^.hk) then begin last:=p; p:=p^.l; end
else p:=p^.r;
end;
if s^.r<>nil then
begin
if last=s then
begin
s^.r^.f:=nil;
s^.r:=nil;
s^.hk:=-maxl;
end
else
begin
splay(s^.r,last);
if last^.l<>nil then last^.l^.f:=nil;
last^.l:=nil;
s^.hk:=calk(s,last);
last^.qk:=s^.hk;
end;
end;
end;
function find(var s:tree;k:double):tree;
var
p:tree;
begin
p:=s;
while p<>nil do
begin
if (p^.qk>=k)and(p^.hk<=k) then exit(p);
if p^.hk>k then p:=p^.r
else p:=p^.l
end;
end;
begin
readln(n,s);
for i:=1 to n do
readln(a[i],b[i],r[i]);
f:=s;
str:=nil;
for i:=1 to n do
begin
if i<>1 then
begin
dc:=find(str,-a[i]/b[i]);
f:=max(f,a[i]*dc^.x+b[i]*dc^.y);
end;
x[i]:=f/(a[i]+b[i]/r[i]);
y[i]:=f/(a[i]*r[i]+b[i]);
inspoint(str,x[i],y[i]);
end;
writeln(f:0:3);
end.