- 组合计数学习笔记
- 组合数
- 组合恒等式
- 二项式反演
- 求组合数
- $1le n,mle 5000$
- $1le n,mle 10^6,p ext{ is a prime number}$
- $1le n,mle 10^{18},1le ple 10^6,p ext{ is a prime number}$
- $1le n,mle 10^{18},1le ple 106,p=p_0c,p_0 ext{ is a prime number}$
- $1le n,mle 10^{18},1le ple 10^6$
- $1le n,mle 10^{9},1le ple 10{18},p=p_0c,p_0 ext{ is a prime number},cle 20,p_0le 60$
- $1le n,mle 2 imes 10^{9},1le ple 2 imes 10^9,p ext{ is a prime number}$
- 斯特林数
- 十二重计数法
- 组合数
组合计数学习笔记
组合数
({nchoose m}) 表示在 (n) 个不同的数中选 (m) 个的方案数。
递推式:枚举最后一个数选还是不选 ({nchoose m}={n-1choose m}+{n-1choose m-1}) 。
通项公式: ({nchoose m}=frac{n!}{(n-m)!m!}) 。
隔板法:
- 将 (n) 个相同的球放到允许空的 (m) 个不同的盒子的方案数是 ({n+m-1choose m-1}) 。
- 将 (n) 个相同的球放到非空的 (m) 个不同的盒子的方案数是 ({n-1choose m-1}) 。
组合恒等式
(n) 个数里面选 (m) 个和选 (n-m) 个本质相同, ({nchoose m}={nchoose n-m}) 。
(n) 个数里面选任意多个可以用二进制表示,一一对应, (sum_{i=0}^n{nchoose i}=2^n) 。
(sum_{i=0}^n2^i{nchoose i}=3^n) , (3^n) 表示有 (n) 个数,每个数 (0sim 2) 的方案数,也可以先从 (n) 个中选出 (i) 个数然后规定这些数大于 (0) ,然后每个数有两个选择 (1) 或者 (2) ,所以乘以一个 (2^i) ,这两种方法等价。
由上面两条启发可以得出一条“套娃定理”:
(sum_{i=0}^n(-1)^i{nchoose i}=[n=0]) ,首先显然有 (sum_{i=0}^0(-1)^i{nchoose i}=1) ,然后 (sum_{i=0}^n(-1)^i{nchoose i}=sum_{i=0}^n(-1)^i({n-1choose i-1}+{n-1choose i})=sum_{i=-1}^{n-1}(-1)^{i+1}{n-1choose i}+sum_{i=0}^n(-1)^i{n-1choose i}=0(nge 1)) 。
(sum_{i=0}^n{nchoose i}[2mid i]=sum_{i=0}^n{nchoose i}[2 otmid i]=2^{n-1}(nge 1)) ,这个式子等价于 (sum_{i=0}^n(-1)^i{nchoose i}=0(nge 1)) 。
(sum_{i=0}^m{n+ichoose n}) 相当于是将 (le m) 个相同的球放到允许空的 (n+1) 个不同的盒子里去的方案数,也可以认为是多加一个盒子变成 (n+2) 个盒子,最后一个盒子作为“垃圾桶”,然后在这些盒子中放 (m) 个相同的球,确定方案后把最后的盒子和里面的球都丢掉,这样和上面一一对应,方案数是 ({n+m+1choose n+1}) ,所以 (sum_{i=0}^m{n+ichoose n}={n+m+1choose n+1}) 。
(sum_{i=m}^n{ichoose m}=sum_{i=0}^{n-m}{m+ichoose m}={n+1choose n-m}={n+1choose m+1}) 。
(n) 个里面选 (m) 个再从 (m) 个里面选 (k) 个和先在 (n) 个里面选 (k) 个再在剩下的 (n-k) 个里面选 (m-k) 个等价, ({nchoose m}{mchoose k}={nchoose k}{n-kchoose m-k}) 。
(sum_{i=0}^k{nchoose i}{mchoose k-i}={n+mchoose k}) ,(n+m) 中选 (k) 个和先把 (n+m) 分成两份 (n) 和 (m) ,然后枚举左边选多少个右边选多少个等价。
(sum_{i=0}^n{nchoose i}^2=sum_{i=0}^n{nchoose i}{nchoose n-i}={2nchoose n}) 。
二项式反演
二项式反演的式子:
证明:
求组合数
求 ({nchoose m}mod p) 。
(1le n,mle 5000)
直接 (mathcal O(nm)) 递推即可。
(1le n,mle 10^6,p ext{ is a prime number})
(mathcal O(n)) 线性递推求逆元,然后根据通项公式 (frac{n!}{m!(n-m)!}) 即可得出答案。
(1le n,mle 10^{18},1le ple 10^6,p ext{ is a prime number})
Lucas 定理:
(1le n,mle 10^{18},1le ple 10^6,p=p_0^c,p_0 ext{ is a prime number})
扩展 Lucas 定理,其实和 Lucas 定理没有什么关系。
考虑把 (n!) 中所有 (p_0) 这个因数提出来,因为提出来之后就可以求逆元了,因数个数还是很好求的,就是 (sum_{i=1}lfloorfrac{n}{p_0^i} floor) ,问题就是把因数提出来之后剩下的值乘起来是多少。
先考虑 (1sim n) 中不是 (p_0) 的倍数的数,这时我们可以分别统计在模 (p) 意义下值为 (i(0<i< p,i otmid p_0)) 的有多少,这个很简单算,就是 (lfloorfrac{n}{p} floor+[nmod pge i]) ,然后全部乘起来即可。
再考虑 (1sim n) 中是 (p_0) 的倍数的数,这样的数的数量是 (lfloorfrac{n}{p_0} floor) ,给所有数提出一个因子 (p_0) ,于是答案就变成 (p_0^{lfloorfrac{n}{p_0} floor}) 乘以一个将 (lfloorfrac{n}{p_0} floor!) 中所有 (p_0) 这个因数提出来之后的值了,直接递归下去求解即可。
(1le n,mle 10^{18},1le ple 10^6)
众所周知,有个东西叫做 CRT (中国剩余定理),然后就是扩展 Lucas 了。
(1le n,mle 10^{9},1le ple 10^{18},p=p_0^c,p_0 ext{ is a prime number},cle 20,p_0le 60)
介绍一个复杂度很诡异的算法,复杂度貌似是 (mathcal O(c^2log_2^3n+cp_0log_2^2n)) 的。。。
和扩展 Lucas 一样的思路,考虑求 (n!) 中的所有 (p_0) 这个因子提出来之后的值,先计算不含 (p_0) 这个因子的所有值的乘积,设:
那么我们要求的就是 (f_n(x)) 的常数项,使用倍增,设 (n=2p_0t+s) ,那么最后暴力乘上后 (s) 项,先考虑前 (2p_0t) 项,假如我们已经求出了 (f_{p_0t}(x)=sum_{i=0}a_{p_0t,i}x^i) ,那么:
注意,我们要求的仅仅是 (f_n(x)) 的常数项,考虑到 (sum_{i=j}a_{p_0t,i}(p_0t)^{i-j}{ichoose j}) 中当 (i-jge c) 时就变成了 (0) ,所以第一次递归下去的时候我们只需要保留 (a_{p_0t,0sim c-1}) 这前 (c) 项就可以求答案了,第二次递归下去的时候我们需要保留 (2c) 项就可以求出前 (c) 项的系数,第三次递归求出保留 (3c) 项……每次计算的时候都是暴力做多项式乘法,还需要多乘上一些余项,第 (i) 层的时间复杂度是 (mathcal O((ic)^2+icp_0)) 的,最多递归 (log_2n) 层,所以复杂度是 (mathcal {O(sum_{i=1}^{log_2n}((ic)^2+icp_0))=O(c^2log_2^3n+cp_0log_2^2n)}) 。
(1le n,mle 2 imes 10^{9},1le ple 2 imes 10^9,p ext{ is a prime number})
众所周知,有一个叫做快速阶乘算法的东西。。。时间复杂度是 (mathcal O(sqrt{n}log_2n)) ,这里就不介绍了,因为我不会。。。
斯特林数
一些记法:
- 上升幂记作 (x^{overline{n}}=prod_{i=0}^{n-1}(x+i)) 。
- 下降幂记作 (x^{underline{n}}=prod_{i=0}^{n-1}(x-i)) 。
不妨规定 (x^{overline{0}}=x^{underline{0}}=1) 。
第一类斯特林数
这里考虑无符号第一类斯特林数。
({nrack m}) 定义为将 (n) 个不同的数分成 (m) 个圆排列(循环)的方案数。
({nrack m}) 也是大小为 (n) 且循环数量为 (m) 的置换数。
递推式:枚举最后一个数的放法(单独成一个圆排列或者放到之前某个数的左边)可以得到 ({nrack m}={n-1rack m-1}+(n-1){n-1rack m}) ;枚举最后一个圆排列大小可以得到 ({nrack m}=sum_{i=1}^n{n-irack m-1}(i-1)!{n-1 choose i-1}) 。
将上升幂展开得到的系数为第一类斯特林数: (x^{overline{n}}=sum_{i=0}^n{nrack i}x^i) 。
考虑到 ([m]x^{overline{n}}=[m]x^{overline{n-1}}(x+n-1)=[m-1]x^{overline{n-1}}+(n-1)[m]x^{overline{n-1}}) ,所以上升幂的递推式和第一类斯特林数相同,初值也相同,所以展开系数就是第一类斯特林数。
第二类斯特林数
({nrace m}) 定义为将 (n) 个不同的数分成 (m) 个集合的方案数( (n) 个不同的球放到 (m) 个相同的盒子)。
递推式:枚举最后一个数的放法(单独成一个集合或者放到之前的某个集合中)可以得到 ({nrace m}={n-1race m-1}+m{n-1race m}) ;枚举最后一个集合的大小可以得到 ({nrace m}=sum_{i=1}^n{n-irace m-1}{n-1choose i-1}) 。
一个恒等式: (n^m=sum_{i=0}^n{nchoose i}{mrace i}i!) 。使用组合意义证明, (n^m) 是将 (m) 个不同的球放到 (n) 个不同的盒子的方案数, (sum_{i=0}^n{nchoose i}{mrace i}i!) 也表示将 (m) 个不同的球放到 (n) 个不同的盒子的方案数:首先枚举有 (i) 盒子非空,然后从 (n) 个盒子选出 (i) 个盒子,然后将 (m) 个不同的球放到 (i) 个相同的盒子里去,然后再乘上 (i!) 变成 (i) 个不同的盒子。
由于 (n^m=sum_{i=0}^n{nchoose i}{mrace i}i!=sum_{i=0}^m{nchoose i}{mrace i}i!) ,所以我们可以得到: (x^n=sum_{i=0}^n{nrace i}{xchoose i}i!=sum_{i=0}^n{nrace i}frac{x!}{i!(x-i)!}i!=sum_{i=0}^n{nrace i}x^{underline{i}}) 。
两类斯特林数
考虑以下两个式子:
这两个式子可以进一步扩展:
证明一下,先要知道这两个式子:
这两个式子还是比较显然的,在草稿本上列一下就可以发现了,由此我们可以得到:
另一个式子:
考虑以下两个式子:
把第二个式子代入第一个式子:
考虑左边的多项式中只有 (x^n) 的系数不为 (0) ,所以我们可以得到:
类似地,考虑以下两个式子:
第二个代入第一个:
考虑左边的上升幂中只有 (x^{overline{n}}) 的系数不为 (0) ,所以我们可以得到:
在这两个式子(这两个式子也被称为反转公式)中:
令 (j=1) ,可以得到:
这两个式子据说比较常用?
有没有觉得之前的式子都挺有对称美?再介绍两个这样优美的式子:
第一个式子和前面讲的递推式 ({nrace m}=sum_{i=1}^n{n-irace m-1}{n-1choose i-1}) 等价,当然也可以用添加一个“垃圾桶”来理解。
第二个式子可以理解为枚举 (i) ,然后把 (n) 分成 (i) 个循环,然后再在 (i) 个循环中选出 (m) 个循环。不妨把 (i) 个循环中选出来的 (m) 个保留,其它的循环和一个额外加入的数 (n+1) 一起放到一个循环中构成 (m+1) 个循环。
为什么这样是一一对应的?不妨认为一个循环中最大的数是这个循环的“标志”,那么把其他的循环和一个额外加入的数 (n+1) 一起放到一起就是首先将所有循环按“标志”从小到大排序,然后将所有循环从“标志”前断开再依次接到 (n+1) 后面,最后再连起来,这样我们就得到了一个新的循环;从新的循环变成若干个循环就是从 (n+1) 前断开变成一个序列,然后从左到右把所有数加入单调递增的单调栈中,最后单调栈中剩下的所有元素就是原先每个循环的“标志”,再从“标志”前断开整个序列,再拼接回去,就得到了原先的若干个循环。由此,这样子做是一一对应的。
难理解是吗?多读几遍就理解了,如果还是理解不了就记结论吧。
斯特林反演
斯特林反演的式子:
证明:
第一个式子~~~
第二个式子~~~
求斯特林数
第一类斯特林数
如何求 ({nrack i}(0le ile m)) ?
用这个式子来求:
将 (x^{overline{n}}) 展开即可得到 ({nrack i}) ,使用倍增展开,设 (f_n(x)=sum_{i=0}^na_{n,i}x^i) ,那么有:
一次卷积可以从 (f_n(x)) 得到 (f_n(x+n)) ,而 (f_{2n}(x)=f_n(x)f_n(x+n)) ,再做一次卷积可以得到 (f_{2n}(x)) ,由此倍增求,时间复杂度是 (mathcal O(nlog_2n)) 的。
如何求 ({irack n}(0le ile m)) ?
感觉这个好像不太好求,不妨考虑使用生成函数,这个式子的组合意义是求 (0sim m) 中每个数分成 (n) 个圆排列的方案数,注意到这些排列是没有区别的,不妨先乘上个 (n!) 变成有序的,构造 (n=1) 时的 EGF :
大小为 (i) 的圆排列给答案贡献时要先乘以一个 ((i-1)!) ,所以要求的就是:
多项式快速幂做到 (mathcal O(nlog_2n)) 。
第二类斯特林数
如何求 ({nrace i}(0le ile m)) ?
考虑这个式子:
二项式反演得到:
一次卷积即可做到 (mathcal O(nlog_2n)) 。
如何求 ({irace n}(0le ile m)) ?
这个也不太好求,再使用一次生成函数,这个式子的组合意义是求 (0sim m) 中每个数分成 (n) 个集合的方案数,这些集合也是没有区别的,所以先乘上 (n!) 变成有序,构造 (n=1) 时的 EGF :
大小为 (i) 的集合对答案贡献时要乘上 (1) ,所以要求的就是:
多项式快速幂做到 (mathcal O(nlog_2n)) 。
十二重计数法
来做一点组合计数的基础练练手吧!
- (n) 个无标号小球( U )/有标号小球( L )。
- (m) 个无标号盒子( U )/有标号盒子( L )。
- 放法无限制( A )/每个盒子至少放一个小球( B )/每个盒子至多放一个小球( C )。
L 表示 labeled , U 表示 unlabeled 。
(1le n,mle 10^5) 。
UUA
小球无标号,盒子无标号,放法无限制。
答案就是把 (n) 分成 (m) 个非负整数之和的方案数,可以用 dp 做,设 (p_{n,m}) 表示把 (n) 分成 (m) 个非负整数之和的方案数,第一种情况是所有数大于 (0) ,第二种情况是存在一个数等于 (0) ,可以写出以下转移方程:
当然也可以枚举最小值是多少,可以写出以下转移方程:
可以发现这其实就是一个完全背包,第 (m) 个物品大小为 (m) ,背包容量是 (n) ,于是问题就变成了付公主的背包(求恰好放满的方案数)。
讲一下付公主的背包是如何实现的,不妨设背包容量为 (m) ,物品数量为 (n) ,第 (i) 个物品大小为 (v_i) 。
首先,大小为 (v) 的物品的生成函数为:
答案就是:
积不好算,考虑取 (ln) 之后变成求和:
如何求 (ln(F_v(x))) ?不妨设 (P(x)=ln(F_v(x))=ln(frac{1}{1-x^v})=-ln(1-x^v)) ,两边同时求导得到:
链式法则: ((f(g(x)))'=f'(g(x))g'(x)) 。 (ln'(x)=frac{1}{x}) 。由此可以得到:
积回去:
所以有:
记录大小为 (v) 的物品数量,然后一次 (mathcal O(mlog_2m)) 得出 (sum_{t=1}^nln(F_{v_t}(x))) ,再 (exp) 回去就行了。
UUB
小球无标号,盒子无标号,每个盒子至少放一个小球。
答案就是划分数,就是把 (n) 分成 (m) 个正数之和的方案数,考虑每个数减 (1) 之后就是非负数了,所以答案就是 (n-m) 分成 (m) 个非负整数之和的方案数,也就是 UUA 。
UUC
小球无标号,盒子无标号,每个盒子至多放一个小球。
每个盒子只有两种情况,放或者不放,又盒子无标号,所以盒子放的数量就是 (n) ,只有在 (mge n) 的时候才可以有方案,所以答案就是 ([mge n]) 。
ULA
小球无标号,盒子有标号,盒子无限制。
隔板法,将 (n) 个相同的球放到允许空的 (m) 个不同的盒子:
ULB
小球无标号,盒子有标号,每个盒子至少放一个小球。
隔板法,将 (n) 个相同的球放到非空的 (m) 个不同的盒子:
ULC
小球无标号,盒子有标号,每个盒子至多放一个小球。
在 (m) 个盒子中选 (n) 来放小球:
LUA
小球有标号,盒子无标号,盒子无限制。
(n) 个数分成 (m) 个可空集合,枚举多少个集合非空:
LUB
小球有标号,盒子无标号,每个盒子至少放一个小球。
(n) 个数分成 (m) 个非空集合,就是第二类斯特林数的定义:
LUC
小球有标号,盒子无标号,每个盒子至多放一个小球。
盒子无标号,每个盒子要么放要么不放,并且放进去的小球就是 (1sim n) ,方案数:
LLA
小球有标号,盒子有标号,盒子无限制。
每个小球 (m) 种选择, (n) 个小球,乘法原理:
LLB
小球有标号,盒子有标号,每个盒子至少放一个小球。
先假设盒子无标号,那么就是 LUB ,再乘上 (m!) 就行了:
LLC
小球有标号,盒子有标号,每个盒子至多放一个小球。
选出哪些盒子放,再把小球放进去就行了:
或者第一个小球 (m) 个选择,第二个小球 (m-1) 个选择……: