多重背包(单调队列优化)

题目大意

    没什么好解释的了==。。。

解题思路

    原本多重背包的做法是三重循环,我们可以用单调队列将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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值