Description
Input
Solution
设dp(i,j)表示选取1-i个物品,剩余为j的方案数。
dp(n+1,m)=1,dp(i,j)=dp(i+1,j)+(i+1,j+a[i])
那么如何统计最终答案呢?
经过上面的讨论,我们可以知道:
设前缀和 sum[i] 表示 从 a[1] 到 a[i] 的和,则对于一个 i 有:
0≤m−sum[i]−j<a[i]
解出花费 j 循环统计即可。
代码
1 const 2 mo=10000007; 3 var 4 n,m,ans:longint; 5 a,sum:array [0..1001] of longint; 6 f:array [0..1001,0..1001] of longint; 7 function min(o,p:longint):longint; 8 begin 9 if o<p then exit(o); 10 exit(p); 11 end; 12 13 procedure init; 14 var 15 i:longint; 16 begin 17 readln(n,m); 18 for i:=1 to n do 19 read(a[i]); 20 end; 21 22 procedure qsort(l,r:longint); 23 var 24 i,j,mid,t:longint; 25 begin 26 if l>r then exit; 27 i:=l; j:=r; 28 mid:=a[(l+r) div 2]; 29 repeat 30 while a[i]<mid do inc(i); 31 while a[j]>mid do dec(j); 32 if i<=j then 33 begin 34 t:=a[i]; a[i]:=a[j]; a[j]:=t; 35 inc(i); dec(j); 36 end; 37 until i>j; 38 qsort(l,j); 39 qsort(i,r); 40 end; 41 42 procedure main; 43 var 44 i,j,k:longint; 45 begin 46 f[n+1,m]:=1; 47 for i:=1 to n do 48 sum[i]:=sum[i-1]+a[i]; 49 if sum[n]<=m then 50 begin 51 ans:=1; 52 exit; 53 end; 54 ans:=0; 55 for i:=n downto 1 do 56 begin 57 j:=sum[i-1]; 58 k:=min(m+1,sum[i-1]+a[i]); 59 while j<k do 60 begin 61 ans:=(ans+f[i+1,j]) mod mo; 62 inc(j); 63 end; 64 for j:=m downto 0 do 65 begin 66 f[i,j]:=(f[i,j]+f[i+1,j]) mod mo; 67 if j+a[i]<=m then 68 f[i,j]:=(f[i,j]+f[i+1,j+a[i]]) mod mo; 69 end; 70 end; 71 end; 72 73 begin 74 init; 75 qsort(1,n); 76 main; 77 writeln(ans); 78 end.