生成函数-背包问题学习笔记
来源:互联网 发布:苹果手机恢复软件 编辑:程序博客网 时间:2024/05/16 15:29
结合 ACdreamer 以及 zhoufenqin 的博客终于弄懂了如何用生成函数解一类特定的大背包问题。
首先要介绍一些重要的公式、数列、函数
由于给你一个生成函数
五边形数:
暂时不管五边形数的实际意义是什么……
前几项:1, 5, 12, 22, 35…
其通项:
然而我们需要的是广义五边形数
具体就是取
前几项:0, 1, 2, 5, 7, 12, 15, 22, 26, 35…(0可能是不需要的具体看情况)
欧拉函数:
百度百科居然只有一个数论欧拉函数……我还在想这怎么展开
此处的欧拉函数是重新定义的
也暂时不管欧拉函数的实际意义是什么
然后假如我们将无穷项全部乘开,会有欧拉函数展开式:
将欧拉函数完全展开后
分拆数:
分拆数的实际意义还是需要理解的:
分拆是指将一个正整数表示成不大于其自身的一个或几个正整数的无序和,分拆数(partition number)则指不同的分拆方式的数目。
将其定义为
小的分拆数是可以用完全背包在
接下来介绍用生成函数的思路求得分拆数的方法
由生成函数的基础知识可以知道分拆数数列的生成函数可以表示为
关键是 之前介绍的欧拉函数的倒数就是这个分拆函数
接下来就是
我们可以得到如下结论:
1. 易知
2.
现在我们举例说明如何求
P的大小写
因此
由此我们可以递推求出
递推式为
直到下标小于0
由五边形数的通项可知总体复杂度为
当然题目没有这么裸,这里还要写一下HDU4658的题解
题意:要求拆分的数中每个数出现的次数不能大于等于k次
生成函数走起
将两个函数乘开后对
代码:
ll five[maxn], p[maxn], cnt;//five是广义五边形数 int cal(int x){ return (3*x*x-x) / 2;}void init(){ /* 此处广义五边形数中那个0并没有求进来,需要注意一下 */ int x = 1; for (cnt = 0; ; ++cnt){ five[cnt] = cal(x); if (five[cnt] > maxn) break; x = x <= 0 ? -x + 1 : -x; } p[0] = 1; for (int i = 1; i < maxn; ++i){ for (int j = 0; i - five[j] >= 0; ++j){ if (j % 4 < 2) p[i] = (p[i] + p[i-five[j]]) % MOD; else p[i] = rule(p[i] - p[i-five[j]]); } }} int n, m;int main(){ int ik, i, j, k, kase; init(); scanf("%d", &kase); while(kase--){ scanf("%d%d", &n, &m); ll ans = p[n]; int sign = -1; for (int i = 0; ; ++i){ if (m * five[i] > n) break; ans = rule(ans + sign*p[n-m*five[i]]); if (i & 1) sign = -sign; } printf("%lld\n", ans); } return 0;}
HDU 6042
题意: 一个体积为
数据特点:以装箱问题的方式做这题的话,
分析:这题是两种限制分拆的糅合①物品不是无限量的,甚至每种物品的数量各不相同②你只有1-n的物品,而不是1-2n的(如果是1-2n的,那可以直接认为是1-
公式推导:
到了这一部分母很好解决,因为我们只关心
最后那个同余等于是因为我们只考虑指数小于等于2n的项
因为最后x的指数是连续的,所以可以用前缀和处理
摘录zhoufenqin博客中一些特别的分拆数:
限制分拆
给一些分拆加限制条件。例如8的分拆有22种,
其中分拆的数中全部都是奇数的有6种:7+1, 5+3, 5+1+1+1, 3+3+1+1, 3+1+1+1+1+1, 1+1+1+1+1+1+1+1;
同样,若要求8分拆的数中是两两不同的也有6种:8, 7+1, 6+2, 5+3, 5+2+1, 4+3+1
PS:这个就是4658中K=1的情况
已证明一个数的分拆中满足以上两种条件的个数是相同的,详见http://en.wikipedia.org/wiki/Glaisher%27s_theorem
一些有关限制分拆的结论:
·n的分拆数中最大部分为m的个数=把n分拆成m部分的个数
如图,左边最大部分m=3,等于把n拆成3部分(右图) 把图转置即可
·n的分拆数中每一部分都小于等于m的个数=把n分成m份或更小
·n的分拆数中每部分的数都相等的个数=n 的因子个数
Eg. 6=2+2+2, 6=3+3,6=1+1+1+1+1+1
·n的分拆数中每部分都是1或2(或者把n分拆成1或2部分)的个数=floor(n/2+1);
Eg. 6=1+1+1+1+1+1, 6=1+1+1+1+2, 6=1+1+2+2, 6=2+2+2
·n的分拆数中每部分都是1或2或3(或者把n分拆成1或2或3部分)的个数=(n+3)^2/12;
- 生成函数-背包问题学习笔记
- 背包问题学习笔记
- 生成函数学习笔记
- 背包问题学习笔记(1)
- 生成函数(背包)-HDU1171
- 0-背包问题笔记
- [笔记]: 背包问题
- 【笔记+代码】背包问题
- 《算法导论》学习笔记——背包问题
- 动态规划学习笔记之0-1背包问题
- 算法学习笔记4-动态规划-背包问题
- 算法学习笔记4-动态规划-背包问题
- 01背包 学习笔记
- 背包问题九讲笔记_01背包
- 背包问题九讲笔记_01背包
- 背包问题九讲笔记_01背包
- 背包九讲笔记-01背包问题
- 背包九讲笔记-完全背包问题
- day07
- LintCode 1.A + B 问题
- ubuntu14.04下安装kinect2驱动及ROS接口(搬运)
- 大数据预科班5
- 生成随机数
- 生成函数-背包问题学习笔记
- 搜索指定栏目下的内容
- Django爬过的坑系列 -- 函数命名
- 原生js实现jq的$.each()方法
- [HDU1512]Monkey King
- 理解各种硬件协议(i2c, spi, lcd等);(9月5日标题暂存)
- C语言实现字符串连接和字符串比较
- HTTP发送请求和接收响应的整个流程
- HDU1686 Oulipo