题目大意
没什么好解释的了==。。。
解题思路
原本多重背包的做法是三重循环,我们可以用单调队列将k的那一重循环进行优化。容易得知对于任意的一个f[j](假设现在第一重循环为i)有可能更新到它的就只有f[j’](j’满足mod w[i]与j同余且j’<j),f[j]有可能更新到的就只有f[j’](j’满足mod w[i]与j同余且j’>j)。也就是说我们可以把j按照mod w[i]的余数将其分为不同的w[i]个部分,且每个部分都是相互独立的。那么对于某一部分的一个状态假如是k,问题就转换成了在这一部分的数中找到一个l,满足l<k且(k-l)/w[i]<=s[i]且f[l]+v[i]*(k-l)/w[i]最大,所以我们就可以用单调队列对这一个状态进行维护,每次只用取队首,也就接近于O(nm)的复杂度了TAT。
type
rec=record
num,value:longint;
end;
const
maxn=250000;
var
state:array[0..maxn] of rec;
tail,head,n,sum,i,j,k:longint;
v,w,c,f:array[0..maxn] of longint;
begin
readln(n);
sum:=0;
for i:=1 to n do
begin
readln(v[i],c[i]);
w[i]:=v[i];
sum:=sum+w[i]*c[i];
end;
sum:=sum div 2;
for i:=1 to sum do
f[i]:=0;
for i:=1 to n do
begin
if c[i]>sum div w[i] then
c[i]:=sum div w[i];
for j:=0 to w[i] do
begin
head:=0;
tail:=0;
for k:=0 to (sum-j) div w[i] do
begin
while (head<=tail) and (state[tail].value<f[k*w[i]+j]-k*v[i]) do
begin
inc(tail);
state[tail].num:=k;
state[tail].value:=f[k*w[i]+j]-k*v[i];
end;
while (state[head].num<j-c[i]) and (head<=tail) do
inc(head);
f[k*w[i]+j]:=state[head].value+v[i]*k;
end;
end;
end;
writeln(f[sum]);
end.