[HAOI2008]硬币购物
Description
Solution
一开始以为是4种物品的多重背包计数,感觉好难写啊,就看题解去了。
结果是容斥??
其实不是很难,不考虑个数限制的话就是一个完全背包计数,先预处理出来\(f[i]\)表示\(i\)元花费的完全背包计数。然后每次去掉不合法的,就是\(f[s-c[i]*(d[i]+1)]\),因为如果不合法,某个东西至少拿\(d[i]+1\)个。容斥一下就好了。
Code
const int N = 100010;
ll c[5], n, d[5], s, f[N];
void main() {
for (int i = 0; i < 4; ++i) c[i] = read();
f[0] = 1;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < N; ++j)
if (j >= c[i]) {
f[j] += f[j - c[i]];
}
n = read();
while (n--) {
for (int i = 0; i < 4; ++i) d[i] = read();
s = read();
ll ans = 0;
for (int i = 0; i < 16; ++i) {
ll cnt = 0, ss = 0;
for (int j = 0; j < 4; ++j) {
if (i >> j & 1) cnt++, ss += c[j] * (d[j] + 1);
}
if (ss > s) continue;
if (cnt & 1)
ans -= f[s - ss];
else
ans += f[s - ss];
}
printf("%lld\n", ans);
}
}
Note
物品个数很小的计数问题可以考虑容斥。