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;
}