DP做法显然大家都能想到,但是一看多组数据,凉了。
我一看(s le 10^5) 显然可以预处理出来无限硬币可组成的情况。
那末,我们可以使用容斥做这题(反正只有4种)。
答案看程序。
关于为什么是 (ans - f_{s-c_{i}cdot (d_{i}+1)}) 笔者也想了很久。
愚以为减掉限定第 (i) 种硬币使用 (d_{i}+1) 枚也就直接减掉了 (d_{i}+n) 枚的情况 ((n in N^{+})) 。因为 (f_{s-c_{i} cdot (d_{i} + 1)})(限定使用 (d_{i} + 1) 枚) 是由 (f_{s - c_{i} cdot (d_{i}+2)}) (限定使用 (d_{i}+2)枚) 转移过来的。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll MAXN = 5e5+10;
ll N, c[10], d[10], f[MAXN];
int main() {
for (ll i = 0; i < 4; i++) {
scanf("%lld", c+i);
}
scanf("%lld", &N);
f[0] = 1;
for (ll i = 0; i < 4; i++) {
for (ll j = c[i]; j <= MAXN - 10; j++) {
f[j] += f[j-c[i]];
}
}
for (ll i = 1; i <= N; i++) {
for (ll i = 0; i < 4; i++) {
scanf("%lld", d+i);
}
ll s;
scanf("%lld", &s);
ll ans = f[s];
for (ll i = 1; i < (1LL << 4); i++) {
ll tmp = 0, tim = 0;
for (ll j = 0; j < 4; j++) {
if (i & (1LL << j)) {
tmp += c[j] * (d[j] + 1);
tim++;
}
}
if (s < tmp) continue;
else {
if (tim & 1) ans -= f[s - tmp];
else ans += f[s - tmp];
}
}
printf("%lld
", ans);
}
return 0;
}