BZOJ2287 消失之物
这题貌似是个权限题qwq,我是用离线题库+本地数据包测的
题目大意:
给你\(n\)个体积分别为\(w[i]\)的物品和容积\(m\),问你将每一件物品分别去掉之后,拼出\(1\)~\(m\)中每一个体积的方案数的个位数分别是多少,将答案矩阵输出。
输入样例:
3 2
1 1 2
输出样例:
11
11
21
考虑先做一次01背包,得到\(f\)数组,然后去掉不合法的方案。怎么去掉呢,首先枚举第\(i\)件物品,令\(g[x]\)表示不用第\(i\)件物品拼成体积为\(x\)的方案数,则\(g\)数组的转移如下:
1.\(x<w[i],g[x]=f[x]\)
2.\(x>=w[i],g[x]=f[x]-g[x-w[i]]\)(可以理解成先限制不选第\(i\)件物品,最后再选上,方案数就是总方案数减去不合法的方案数)
然后输出\(g\)数组就行了:
#include <bits/stdc++.h>
using namespace std;
#define N 2000
int n, m, w[N+5], f[N+5], g[N+5];
int main()
{
//freopen("2287.in", "r", stdin);
//freopen("2287.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &w[i]), w[i] = w[i] > m ? m+1 : w[i];
f[0] = 1;
for(int i = 1; i <= n; ++i)
for(int j = m; j >= w[i]; --j) f[j] = (f[j]+f[j-w[i]])%10;
for(int i = 1; i <= n; ++i)
{
for(int j = 0; j < w[i]; ++j) g[j] = f[j];
for(int j = w[i]; j <= m; ++j) g[j] = ((f[j]-g[j-w[i]])%10+10)%10;
for(int j = 1; j <= m; ++j) printf("%d", g[j]);
printf("\n");
}
return 0;
}