安吉D4-A
808 字
4 分钟
安吉D4-A
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1
- 40安吉D6-T3
- 41安吉-开营测试 T4
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A本文
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
我们发现这道题是一个物品数很少的多重背包问题,但显然,使用多重背包会超时.
因此,我们尝试将其转化为完全背包.
观察到完全背包和多重背包的区别只在于限制,我们先无视限制,跑一次完全背包.
dp[0] = 1;for (int i = 1; i <= 4; i++) { for (int j = c[i]; j <= N; j++) { dp[j] += dp[j - c[i]]; }}显然,这样的方案数比目标方案数大,多出了:
至少有 1 种数值的硬币超出限制
这样的方案.
为了计算出多出的方案数,我们可以使用容斥.定义 表示第 种硬币( 是一个集合且满足 )必须超出限制,其余不管.
则至少有 1 种数值的硬币超出限制的答案 :
最终答案为:.
问题是,如何求 ?
以 为例,需要统计第 2 种和第 4 种硬币超出限制的方案数,那么,只需要固定第 2 种有 个,用掉 元,第 4 种有 个,用掉 元,将这些当成已知,剩余的需要分配的元数为 , 就等于 .
标程
#include <bits/stdc++.h>using namespace std;#define int long longconst int N = 1e5 + 100;int c1, c2, c3, c4, d1, d2, d3, d4, d5, s;int dp[N], c[5], d[5];// dp[i][j] 考虑到前i种硬币,总价值为j的方案数// 不存在硬币超出 = 无限制 - (必须1种超出) + (必须2种超出) - (必须3种超出) +// (必须4种超出)signed main() { cin >> c[1] >> c[2] >> c[3] >> c[4]; int T; cin >> T; dp[0] = 1; for (int i = 1; i <= 4; i++) { for (int j = c[i]; j <= N; j++) { dp[j] += dp[j - c[i]]; } } while (T--) { cin >> d[1] >> d[2] >> d[3] >> d[4] >> s; int ans = 0; // 子集枚举 for (int st = 0; st < (1 << 4); st++) { int cur = s, vaild = 0; for (int i = 0; i < 4; i++) { if (st & (1 << i)) { vaild++; cur -= (d[i + 1] + 1) * c[i + 1]; } } if (cur >= 0) ans += (vaild % 2 ? -1 : 1) * dp[cur]; } cout << ans << endl; }}正难则反,正着思考问题没有结果不妨反过来思考.
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


