題目鏈接:bzoj2287
題目大意:
ftiasch 有 N 個物品, 體積分別是 W1, W2, …, WN。 由於她的疏忽, 第 i 個物品丟失了。 “要使用剩下的 N - 1 物品裝滿容積爲 x 的揹包,有幾種方法呢?” – 這是經典的問題了。她把答案記爲 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i, x) 表格。
題解:
揹包+容斥?
我真的,感覺自己什麼都不會qwq
話說一個物品只能取一次啊只能取一次啊。
設f[i][j]表示取前i個滿j的方案數 可以只用一維
c[i][j]表示第i個不取,裝滿容積爲j的揹包的方案數,就是答案
先
c[i][j]的話有三種情況:
- 若j=0,則c[i][j]=1,顯然
- 若j<v[i],那麼j中一定不會取到第i個物品,於是c[i][j]=f[j]
- 若j≥v[i],那麼它就等於總的方案數減去選到了第i個物品的方案數。
有c[i][j]=f[j]-c[i][j-v[i]],爲什麼c[i][j-v[i]]表示選到了第i個物品的方案數呢?因爲c[i][j-v[i]]表示的是不含i裝了j-v[i]的方案數那麼它加上v[i]之後不就是含i的裝滿了j的嗎
所以真正有用的代碼只有四行。
而我,並不會做。
真是個悲傷個故事。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 2010
int v[maxn],f[maxn],c[maxn][maxn];
//f[i][j]表示取前i個滿j的方案數 可以只用一維
//c[i][j]表示第i個不取,裝滿容積爲j的揹包的方案數
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int i,j,n,m;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) scanf("%d",&v[i]);
memset(f,0,sizeof(f));f[0]=1;
for (i=1;i<=n;i++)
for (j=m;j>=v[i];j--)
f[j]=(f[j]+f[j-v[i]])%10;
for (i=1;i<=n;i++)
for (j=0;j<=m;j++)
{
if (j==0) c[i][j]=1;
else if (j<v[i]) c[i][j]=f[j]%10;
else c[i][j]=(f[j]-c[i][j-v[i]]+10)%10;
}
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
printf("%d",c[i][j]%10);
printf("\n");
}
return 0;
}