bzoj1042

首先直接做多重背包肯定会TLE的,

观察这个背包问题有什么特殊性呢

物品种类和重量,价值是一定的,不同的是背包的容量和物品的数量

由于当物品数量没有限制的时候,方案数是可以预处理出来的

所以我们考虑用ans=物品数量没有限制时的方案数-物品超出限制的方案数来解决

第一部分是可以用完全背包来解决的

第二问不难想到用容斥原理来解决

设f[m]为容量为m时的方案数

假如当i号物品超出数量s[i]限制(不知道其他物品有没有超),方案数f[m-w[i]*(s[i]+1)](严格超出限制

以此类推,可得出多个物品超出限制的方案数

根据容斥原理,计算一下即可

 1 var f:array[0..100010] of int64;
 2     w:array[1..4] of longint;
 3     c:array[0..1010,0..4] of longint;
 4     t:array[0..1010] of longint;
 5     i,n,j,k,p,y,m,s:longint;
 6     ans:int64;
 7 
 8 begin
 9   for i:=1 to 4 do
10     read(w[i]);
11   readln(n);
12   for i:=1 to n do
13   begin
14     for j:=1 to 4 do
15       read(c[i,j]);
16     readln(t[i]);
17     if t[i]>m then m:=t[i];
18   end;
19   f[0]:=1;
20   for i:=1 to 4 do
21     for j:=w[i] to 100000 do
22       f[j]:=f[j]+f[j-w[i]];
23 
24   for i:=1 to n do
25   begin
26     ans:=0;
27     for j:=0 to 15 do   //用二进制表示物品是否超出限制
28     begin
29       s:=t[i];
30       y:=0;
31       for k:=1 to 4 do
32       begin
33         p:=1 shl (k-1);
34         if j and p<>0 then
35         begin
36           s:=s-w[k]*(c[i,k]+1);
37           if s<0 then break;
38           inc(y);
39         end;
40       end;
41       if s<0 then continue;   //注意可能不存在某几个物品都超出限制的情况
42       if y mod 2=1 then ans:=ans-f[s] else ans:=ans+f[s];
43     end;
44     writeln(ans);
45   end;
46 end.
View Code
原文地址:https://www.cnblogs.com/phile/p/4473179.html