洛谷P4141消失之物(背包经典题)——Chemist

题目地址:https://www.luogu.org/problemnew/show/P4141

分析:这题当然可以直接暴力枚举去掉哪一个物品,然后每次暴力跑一遍背包,时间复杂度为O(m*n^2),显然超时。由于算去掉哪一个物品比较复杂,我们可以考虑容斥,算出他的补集,也就是选这个物品的方案数,然后用全集减去他的补集得到答案。算全集的过程就是跑一遍01背包,时间复杂度O(n^2),然后枚举去掉的物品i,再枚举背包的容积就j,算选择这个物品凑出这个容积的方案数就相当于算凑出j-w[i]的方案数,然后再强制选择一个i物品,用前面第一遍背包预处理求出的答案减去这个就是最终答案。然而我们还需要考虑一种情况,就是当前枚举的容积小于i物品的体积,也就是说在凑出j体积的背包时一直都没有选择i物品,也就不能去掉它,答案就是前面01背包预处理的值。

代码:

#include<bits/stdc++.h>
using namespace std;
const int M=2e3+10;
int n,m,w[M],f[M],g[M]; 
int main()
{
	scanf("%d%d",&n,&m); 
	for(int i=1;i<=n;i++)
	 scanf("%d",&w[i]);
	f[0]=1;
	//01背包: 
	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++)
	{
		memset(g,0,sizeof(g));
		g[0]=1;
		for(int j=1;j<=m;j++)
		{
			if(j>=w[i])g[j]=(f[j]-g[j-w[i]]+10)%10;
			else g[j]=f[j];
			printf("%d",g[j]);
		}
		puts("");
	}
	return 0;
} 

  

posted @ 2018-08-18 15:10  cellur925&Chemist  阅读(300)  评论(0编辑  收藏  举报