JZOJ链接 (原题BestCoder Round #59 (div.1) B)
题目大意直接看题吧
首先很容易想到这是一个一维的背包问题
但是由于不同的时间打怪有不同的效益
所以我们需要决定的是打怪的顺序
假设最优答案的打怪顺序为p1,p2,p3…pm
那么对于任意两个相邻怪物pi,pi+1
调换顺序不会使得其更优
由于两个怪物需要打的时间相同
所以调换两个相邻怪物不会使其他怪物的贡献有影响,因此我们只用关心两个相邻怪物就好了
依然是对于怪物i,i+1而言
如果我们先打i,我们失去的收益为
如果我们先打i+1,我们失去的收益为
因此如果,则先打pi更优
移项可得
由此可得最优的答案顺序中是递减的
因此我们把怪物的从大到小排列
之后就是一个一维背包问题了
设表示用i分钟达到的最大收益
转移公式为
最后统计其中最大的即可
代码
var
a,b,c:array[0..1000] of longint;
rt:array[0..1000] of extended;
f:array[-3000..3000] of int64;
tt,n,m,i,j,k:longint;
ans:int64;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure qsort(l,r:longint);
var
i,j,t:longint;
mid,et:extended;
begin
i:=l;
j:=r;
mid:=rt[(i+j) div 2];
repeat
while rt[i]>mid do inc(i);
while rt[j]<mid do dec(j);
if i<=j then
begin
et:=rt[i];rt[i]:=rt[j];rt[j]:=et;
t:=a[i];a[i]:=a[j];a[j]:=t;
t:=b[i];b[i]:=b[j];b[j]:=t;
t:=c[i];c[i]:=c[j];c[j]:=t;
inc(i);
dec(j);
end;
until i>j;
if j>l then qsort(l,j);
if i<r then qsort(i,r);
end;
begin
readln(tt);
repeat
readln(n,m);
for i := 1 to n do
begin
readln(a[i],b[i],c[i]);
rt[i]:=b[i]/c[i];
end;
qsort(1,n);
fillchar(f,sizeof(f),0);
for j := 1 to n do
begin
for i := m downto 0 do
begin
if i-c[j]>=0 then f[i]:=max(f[i],f[i-c[j]]+a[j]-i*b[j]);
end;
end;
ans:=0;
for i := 0 to m do if ans<f[i] then ans:=f[i];
writeln(ans);
dec(tt);
until tt=0;
end.