bzoj1042_递推加容斥原理
来源:互联网 发布:ubuntu如何安装eclipse 编辑:程序博客网 时间:2024/06/07 20:52
又一道容斥原理的题目。
最开始看的时候只会打暴力, 想到了正常的dp, 实在想不出来了, 就厚着脸皮去看题解。 最近老是在做这一类的事情, 看完题解之后又感觉很简单... 容斥原理的题目果然还是不熟悉啊。 当然了, 看题解的时候比较喜欢那些有详细证明的, 因为没有证明自己想会很累(我好懒啊)。
这道题的关键点自然还是容斥原理, 对于四种硬币的使用情况, 如果我们记有i种使用过度的方案数为g[i]的话, 那么答案ans = g[4] - g[3] + g[2] - g[1], 这是由容斥原理直接得到的。 剩下的事情就是求g[i]。 其实这是一个抽象的过程, 我们最后用递归来实现就行了, 而不是去求g[]数组。 不妨设第一类硬币使用过度, 即使用量超过了lim[1], 那么剩下的可任取, 也就是说这个时候的情况数与没有限制地取到sum-(c[1]*(lim[1]+1))的情况数是相同的, 因为一旦使用的量多于d[1]后其他情况就无所谓了, 对于其他类别的硬币有同样的情况。 至于没有限制时的情况, 我想用递推很快就可以算出来了吧。
构造一个搜索框架, 记录先前有几种硬币使用过度st, 由最开始ans的表达式我们可以知道st为奇数时, ans需减掉这个数, 反则加上这个数, 因此在进行了越界的决策后, 我们要让st变量自取反, 这样就得到了代码中的dfs函数。
#include <cstdio>#define N 100000 + 10using namespace std;typedef long long LL;int m, t, c[4], lim[4];LL f[N], ans;void first(){ f[0] = 1; for (int i = 0; i < 4; ++i) for (int j = c[i]; j <= 100000; ++j) f[j] += f[j-c[i]];//递推求无限制时的方案数}void init(){ for (int i = 0; i < 4; ++i) scanf("%d", &lim[i]); scanf("%d", &m);}void dfs(int x, int sum, int st){ if (sum < 0) return;//不存在的情况 if (x == 4) { if (st & 1) ans -= f[sum]; else ans += f[sum];//st代表是奇数过量还是偶数过量 return; } dfs(x+1, sum, st); dfs(x+1, sum-(c[x]*(lim[x]+1)), !st);//进行当前硬币过量的决策}void deal(){ ans = 0; dfs(0, m, 0);//初始状态 printf("%lld\n", ans);}int main(){ for (int i = 0; i < 4; ++i) scanf("%d", &c[i]); scanf("%d", &t); first(); while(t--) { init(); deal(); } return 0;}
0 0
- bzoj1042_递推加容斥原理
- 原理
- 原理
- 原理
- 加法原理乘法原理
- Win32ASM原理
- win32asm原理
- 编译原理
- 创新原理
- 数字签名原理
- 变速箱原理
- 搜索引擎原理
- 乱码原理
- 搜索引擎原理
- 搜索引擎原理
- 彼得原理
- 缩略图原理
- Winlogon原理
- C#和Java实现互通的RSA&DES加解密算法(一)
- java数组(定义、赋值和初始化)
- iOS之AutoresizingMask, autoresizesSubviews
- Hbase 学习笔记: Hbase的架构和实现原理
- PHP simplexml解析结果需要进行强制类型转换
- bzoj1042_递推加容斥原理
- Oracle数据库的varchar2(2)存储一个汉字时提示插入汉字过长问题
- CXF学习笔记(1)-HelloWorld!-发布webservice .
- 表单提交检测
- PHP通用分页(Pager)类
- Android 修改drawableTop 图片的大小
- ios--图片处理(修改、保存)
- Android开源项目和框架
- 无论发生什么都不要失望,不要丢掉希望