B-Station
试题描述
在离著名的国家Berland不远的地方,有一个水下工作站。这个工作站有N层。已知:是第i层装有Wi的水,最多可以容纳Li的水,恐怖分子炸毁第i层的代价是Pi。第i层一旦被炸毁,该层所有的水都将倾泻到第i+1层。如果某一层的水量超过了它的容量(即Li),那么该层就将自动被毁坏,所有的水也会倾泻到下一层。
Pivland的恐怖分子想要用最少的钱毁掉第N层,现在他雇佣你来计算,需要炸毁哪些层。
输入
第一行有一个自然数N(1<=n<=15000)。接下来的N行,每行3个整数Wi, Li, Pi(0<=Wi,Li,Pi<=15000)。
输出
输出需要炸毁的层的编号。
样例
Input
3
1000 1000 1
0 1000 2
2 10 100
Output
1
2
=====================
=================
朴素
-------------------
type
node=record
w,l,p:longint;
end;
var
n:longint;
ti:array[0..150000]of node;
procedure init;
begin
assign(input,'bstation.in');
assign(output,'bstation.out');
reset(input); rewrite(output);
end;
procedure terminate;
begin
close(input); close(output);
halt;
end;
procedure main;
var
i,j:longint;
ans,w,k:longint;
s:longint;
begin
readln(n);
for i:=1 to n do
readln(ti[i].w,ti[i].l,ti[i].p);
ans:=ti[n].p; s:=n;
for i:=n-1 downto 1 do //枚举从i开始炸
begin
k:=ti[i].p;
w:=ti[i].w;
if k>ans then continue;
for j:=i+1 to n do
begin
w:=w+ti[j].w;;
if w<=ti[j].l then
begin
k:=k+ti[j].p;
if k>ans then break;
end;
end;
if k<ans then
begin
ans:=k;
s:=i;
end;
end;
w:=ti[s].w;
writeln(s);
for i:=s+1 to n do
begin
w:=w+ti[i].w;
if w<=ti[i].l then writeln(i);
end;
end;
begin
init;
main;
terminate;
end.
_________________________________
堆优化
---------------------------
var
n:longint;
sum,w,l,p:array[0..150000]of longint;
dui:array[0..150000]of longint;
dui_s:longint;
procedure init;
begin
assign(input,'bstation.in');
assign(output,'bstation.out');
reset(input); rewrite(output);
end;
procedure terminate;
begin
close(input); close(output);
halt;
end;
procedure shift(r,n:longint);
var
k:longint;
tem:longint;
begin
k:=2*r;
if (k+1<=n) and (sum[dui[k+1]]-l[dui[k+1]]>sum[dui[k]]-l[dui[k]])
then inc(k); //保证大根堆..
while (k<=n)and(sum[dui[k]]-l[dui[k]]>sum[dui[r]]-l[dui[r]]) do
begin
tem:=dui[k];
dui[k]:=dui[r];
dui[r]:=tem;
r:=k;
k:=2*r;
if (k+1<=n) and (sum[dui[k+1]]-l[dui[k+1]]>sum[dui[k]]-l[dui[k]])
then inc(k); //保证大根堆..
end;
end;
procedure adjust(r:longint);
var
k:longint;
tem:longint;
begin
k:=r shr 1;
while ((k>0) and (sum[dui[k]]-l[dui[k]]<sum[dui[r]]-l[dui[r]])) do
//保证上面的比较大..
begin
tem:=dui[k];
dui[k]:=dui[r];
dui[r]:=tem;
r:=k;
k:=r shr 1;
end;
end;
procedure main;
var
i,j:longint;
ans:longint;
t:longint;
s:longint;
water:longint;
begin
readln(n);
sum[0]:=0;
for i:=1 to n do
begin
readln(w[i],l[i],p[i]);
sum[i]:=sum[i-1]+w[i];
end;
ans:=p[n];
dui_s:=0;
inc(dui_s);
dui[dui_s]:=n; //入堆
t:=ans;
for i:=n-1 downto 1 do
//表示从i开始炸.
begin
t:=t+p[i]; //记录变化{由上一次的状态而来}..
inc(dui_s);
dui[dui_s]:=i;
adjust(dui_s); //调整堆..
while sum[dui[1]]-l[dui[1]]>sum[i-1] do //当不用炸的时侯
begin
t:=t-p[dui[1]]; //减去那个不需要炸得价值..
dui[1]:=dui[dui_s];
dec(dui_s);
shift(1,dui_s);
end;
if t<ans then
begin
ans:=t;
s:=i;
end;
end;
water:=w[s]; writeln(s);
for i:=s+1 to n do
begin
water:=water+w[i];
if water<=l[i] then writeln(i);
end;
end;
begin
init;
main;
terminate;
end.