bzoj 2287消失之物 (退背包)

题目链接:https://darkbzoj.tk/problem/2287

\(f[x]\)表示普通0/1背包的计数
\(g[x]\)表示不选当前物品,装满x体积的方案数
正难则反
如果\(w[i]>x\),则不可能被选,\(g[x] = f[x]\)
如果\(w[i]<=x\),则考虑总方案数减去选了i的方案数,即\(g[x] = f[x] - g[x-w[i]]\)

0/1背包计数初始值的问题,不会被背到的数结果始终是零,所以不用初始化

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 2010;
const int M = 10;

int n,m;
ll f[maxn],g[maxn],w[maxn];

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
	n = read(), m = read();
	for(int i=1;i<=n;++i) w[i] = read();
	
//	memset(f,-1,sizeof(f));
	f[0] = 1;
	for(int i=1;i<=n;++i){
		for(int j=m;j>=w[i];--j){
			if(f[j-w[i]] != -1) f[j] = (f[j] + f[j-w[i]]) % M;
		}
	}
	
	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]] + M) % M;
		}
		for(int j=1;j<=m;++j) printf("%d",g[j]); printf("\n");
	}
	
	return 0;
}
posted @ 2020-10-22 23:36  Tartarus_li  阅读(212)  评论(0编辑  收藏  举报