Description
ftiasch 有
n
n
n 个物品, 体积分别是
w
1
,
w
2
,
…
,
w
n
w_1,w_2,\dots,w_n
w1,w2,…,wn。由于她的疏忽,第
i
i
i 个物品丢失了。
“要使用剩下的
n
−
1
n-1
n−1 物品装满容积为
x
x
x 的背包,有几种方法呢?”——这是经典的问题了。
她把答案记为
cnt
(
i
,
x
)
\text{cnt}(i,x)
cnt(i,x) ,想要得到所有
i
∈
[
1
,
n
]
i \in [1,n]
i∈[1,n],
x
∈
[
1
,
m
]
x \in [1,m]
x∈[1,m] 的
cnt
(
i
,
x
)
\text{cnt}(i,x)
cnt(i,x) 表格。
Solution
法1(之前的方法,略麻烦一点)
f
(
i
,
j
)
f(i,j)
f(i,j)代表使用前i个物品填满j的空间的方案数
F
(
i
,
j
)
=
f
(
i
−
1
,
j
)
+
f
(
i
−
1
,
j
−
w
(
i
)
)
,
f
(
0
,
0
)
=
1
F(i,j)=f(i-1,j)+f(i-1,j-w(i)),f(0,0)=1
F(i,j)=f(i−1,j)+f(i−1,j−w(i)),f(0,0)=1
c
(
i
,
j
)
c(i,j)
c(i,j)表示
c
o
u
n
t
(
i
,
j
)
,
count(i,j),
count(i,j),分三种情况
1
,
j
>
=
w
(
i
)
,
c
(
i
,
j
)
=
f
(
n
,
j
)
−
c
(
i
,
j
−
w
(
i
)
)
1,j>=w(i),c(i,j)=f(n,j)-c(i,j-w(i))
1,j>=w(i),c(i,j)=f(n,j)−c(i,j−w(i))即用填满j的总方案数
(
f
(
n
,
j
)
)
(f(n,j))
(f(n,j))减去使用了第
i
i
i个物品的方案数,其中使用第i个物品填满j的空间的方案数等于使用其余物品填满
j
−
w
(
i
)
j-w(i)
j−w(i)的空间的方案数
(
c
(
i
,
j
−
w
(
i
)
)
)
(c(i,j-w(i)))
(c(i,j−w(i)))。
3
,
0
<
j
<
w
(
i
)
,
c
(
i
,
j
)
=
f
(
n
,
j
)
3,0<j<w(i),c(i,j)=f(n,j)
3,0<j<w(i),c(i,j)=f(n,j),此时无论怎么填,都不会用到第
i
i
i个物品,答案所以等于总方案数。
4
,
j
=
0
,
c
(
i
,
j
)
=
1
4,j=0,c(i,j)=1
4,j=0,c(i,j)=1
法2:
对于下面的 f f f来讲,顺序是没有关系的(不管先转移哪个物品,总的意义都是这 n n n个物品放入大小为 m m m的空间)
for (j=m;j>=w[i];j--) f[j]+=f[j-w[i]];
所以假如我们现在在处理扔掉 i i i的情况,我们可以假设我们之前处理的最后一轮是 i i i,然后倒推回去
memcpy(g,f,sizeof f);
for (j=w[i];j<=m;++j) g[j]-=g[j-w[i]];
Code
#include<bits/stdc++.h>
using namespace std;
const int N=2001;
int n,m,i,j,w[N],f[N],t[N];
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(){
int x=0,fl=1;char ch=gc();
for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
return x*fl;
}
int main(){
n=rd();m=rd();
f[0]=1;
for (i=0;i<n;i++){
w[i]=rd();
for (j=m;j>=w[i];j--) (f[j]+=f[j-w[i]])%=10;
}
for (i=0;i<n;i++,puts(""))
for (t[0]=1,j=1;j<=m;j++) t[j]=(f[j]-(j>=w[i])*t[j-w[i]])%10,putchar((t[j]+10)%10|48);
}