Description
ar把一段凹凸不平的路分成了高度不同的N段,并用H[i]表示第i段高度。现在Tar一共有n种泥土可用,它们都能覆盖给定的连续的k个部分。
对于第i种泥土,它的价格为C[i],可以使得区间[i,min(n,i+k-1)] 的路段的高度增加E[i]。
Tar要设定一种泥土使用计划,使得使用若干泥土后,这条路最低的高度尽量高,并且这个计划必须满足以下两点要求:
(1)每种泥土只能使用一次。
(2)泥土使用成本必须小于等于M。
请求出这个最低的高度最高是多少。
Input
第一行为如上文所示的三个正整数:N,M,K。
接下来N行,每行3个如上文所示的正整数H[i],E[i],C[i]。
Output
输出有且只有一个数字,为最底部分的高度的最大值
Sample Input
4 20 1
1 3 5
1 7 3
4 6 9
3 5 13
Sample Output
3
Data Constraint
对于30%的数据:N≤20。
对于100%的数据:1≤K≤11,1≤N≤100,0≤M,H[i],E[i],C[i]≤1000000。
分析:
一看题目,最小值最大,就知道应该是二分逼近求解,关键时看当前的值是否可以满足条件,也就是对于高度high,能否用m的钱把所有都增加到high及以上高度。这个判断要用dp完成(考试是愣是想不出来)。
设f[i,s]为把前i个部分升到high,i前面k个部分选取状态为s时的最小花费。
sum[i,s]也是前i个部分升到high,i前面k个部分选取状态,前面k个可以为i这个部分增加的高度。
因为一个点的状态之和他前面的k个部分有关,不需要记录所有状态。
当前点的状态s,只能由两个点转移过来,即
d和d+2^(k-1) {d=s shr 1}
(如:01这个状态,说明前一个数没有选,则是由00或10转移过来)
则
如果s为偶数,也就是当前点不用,有
f[i,s]=min(f[i-1,d],f[i-1,d+2^(k-1)]);
sum[i,s]=sum[i-1,d];
如果s为奇数,则当前点要选用,有
f[i,s]=min(f[i-1,d],f[i-1,d+2^(k-1)])+w[i] (w[i]为使用i的花费)
sum[i,s]=sum[i-1,d]+v[i] (v[i]为可以为i这个部分增高的高度)
当然,我们对于每个状态都有判断该状态下的sum[i,s]+h[i]>=high是否成立,h[i]为i部分开始高度,若不成立,则该状态不合法,把f[i,s]变为maxlongint即可。
最后判断f[n,s]中是否有一个状态是花费小于等于m的,如果有,则该高度可以达到。
代码:
var
f,sum:array [0..101,0..2100] of longint;
h,w,v:array [-11..101] of longint;
n,m,k,i,j,l,r,ans,mid:longint;
function min(x,y:longint):longint;
begin
if x>y then exit(y)
else exit(x);
end;
function max(x,y:longint):longint;
begin
if x>y then exit(x)
else exit(y);
end;
procedure init;
var i,j:longint;
begin
for i:=0 to 101 do
for j:=0 to 2100 do
begin
f[i,j]:=maxlongint div 3;
sum[i,j]:=-maxlongint div 3;
end;
end;
function dp(high:longint):boolean;
var i,j:longint;
s,d,e,q:longint;
begin
init;
sum[0,0]:=0;
f[0,0]:=0;
d:=1 shl k-1;
q:=1 shl (k-1);
for i:=1 to n do
begin
for s:=0 to d do
begin
e:=s shr 1;
if s mod 2=0 then
begin
f[i,s]:=min(f[i-1,e],f[i-1,e+q]);
sum[i,s]:=max(sum[i-1,e],sum[i,s]);
if sum[i,s]+h[i]<high then f[i,s]:=maxlongint div 3;
end
else
begin
f[i,s]:=min(f[i-1,e],f[i-1,e+q])+w[i];
sum[i,s]:=max(sum[i-1,e]+v[i],sum[i,s]);
if sum[i,s]+h[i]<high then f[i,s]:=maxlongint div 3;
end;
end;
end;
for s:=0 to d do
if f[n,s]<=m then exit(true);
exit(false);
end;
begin
assign(input,'cover.in');
assign(output,'cover.out');
reset(input);
rewrite(output);
readln(n,m,k);
for i:=1 to n do
readln(h[i],v[i],w[i]);
l:=0; r:=maxlongint;
while l<=r do
begin
mid:=(l+r) shr 1;
if dp(mid) then
begin
l:=mid+1;
if mid>ans then ans:=mid;
end
else
r:=mid-1;
end;
writeln(ans);
close(input);
close(output);
end.