大概是组合计数问题的基础,因此稍微写一下。
或者说,尝试复习,发现自己都不会了,所以应该写一下。
约定
这一类问题都可以在问题确定是,用两个参数 \(n,r\) 来描述。其中 \(n\) 表示球数, \(r\) 表示盒数。
为了方便描述,以下用一串二进制码表示问题的状态。例如 0101
:
- 第一位表示球是否相同。
0
表示相同,1
表示不同; - 第二位表示盒是否相同。
0
表示相同,1
表示不同; - 第三位表示球可否不放。
0
表示不可,1
表示可以; - 第四位表示盒可否为空。
0
表示不可,1
表示可以;
因此状态 0101
就表示:球相同,盒不同,球不可不放,盒可以为空,此时的方案数。
另外,由于有些问题是笔者自己 yy 的,因此正确性存疑,该类问题用 *
标注。如果发现该部分有问题,请及时留言。
11--
球不同、盒不同问题求解的基本途径是乘法原理。
1101
对于每一个球,它都有 \(r\) 种选择。由于每个球不同,因此它们的选择相互独立,可以直接乘起来。
因此可以得到总方案数为 \(r^n\) ,求解的时间复杂度是 \(O(\log_2n)\) 。
1100
此时盒子不可以为空,但是直接乘法原理我们会得到盒子为空的方案。
注意乘法原理求到的是 " 至少有 0 个盒子为空 " 的方案数。因此不难想到用容斥原理计算。枚举一下空盒子的数量,就可以方案数是:
求解的时间复杂度是 \(O(r\log_2n)\) 。
在 \(r\) 比较小的情况下,可以 \(O(r)\) 预处理自然数幂,然后求式子,时间复杂度是 \(O(r)\) 。
还可以发现,如果用指数型生成函数描述这个式子,我们可以在 \(O(r\log_2r)\) 的时间批量求出不同的 \(r\) 的解。
你会在之后再见到它的。
1110
这个时候,每个球就多了一个 " 不放 " 的选择。因此每个球有 \(r+1\) 种选择。总方案数是 \((r+1)^n\) 。
1111
继续容斥:
01--
球相同、盒不同问题求解的基本原理是隔板法。
0101
想象 \(n\) 个球排成一列。此时由于盒子是有区别的,因此我们可以将球分成 \(r\) 组,然后第一组放进第一个盒子里,第二组放进第二盒......第 \(r\) 组放进第 \(r\) 盒。因此我们就考虑计算将 \(n\) 个球分成 \(r\) 组的方案数。
显然这是隔板法的问题。 \(n\) 个球有 \(n-1\) 个缝,从 \(n-1\) 个缝中选出 \(r-1\) 个来插板的方案数是 \(\binom{n-1}{r-1}\) 。
0100
盒子可以为空,因此直接放板子不太对头。经典的思想是:
我们给每个盒子先放一个 " 假球 " ,这样总共有 \(n+r\) 个球,并且每个盒子至少有一个球(包括 " 假球 " )。现在再进行隔板法就没有问题了,方案就是 \(\binom{n+r-1}{r-1}\) 。
0110*
由于球本身没有区别,因此有球没放就相当于球的数量变少了。于是就可以直接枚举球的数量:
这个组合含义也比较显然。我们同样可以假想一个盒子,用来装 " 没放 " 的球。由于最后这个盒子可以为空,因此总共有 \(n\) 个缝, \(r\) 个板。
注意,盒子不能为空,因此这里不考虑不放球的情况。
0111*
同理易得:
组合意义请自行思考。
注意,盒子可以为空,因此这里需要考虑球都不放的情况。
10--
球不同、盒相同问题求解的基本途径是第二类斯特林数。
1000
此时直接推导难度比较大,因此我们考虑使用 DP 。
\(f(i,j)\) :有 \(i\) 个球, \(j\) 个盒子,且球不同,盒相同时,球必须放,盒不能空的放球的方案数。
考虑转移:
最后一个转移是在讨论,在放最后一个球时,是否要新拿盒子。如果新拿一个,就是 \(f(i-1,j-1)\) 。如果不新拿,就从前 \(j\) 个盒子中挑一个放进去。
如果你有所了解,你就会发现,这是第二类斯特林数的递归式。这里我们记 \({n\brace r}=f(n,r)\) 。
因此这个问题的答案是 \(n\brace r\) 。
另一种推导方式 是,考虑容斥。我们先给盒子标号,然后枚举空盒子的数量,最后把标号除掉:
可以发现,后面的容斥式实际就是 1100
的解。因此 1100
的解也可以表述为 \(r!{n\brace r}\) 。
另外,根据这个容斥式也可以使用 NTT 在 \(O(n\log_2n)\) 的时间内求出 \({n\brace 0},{n\brace 1},\dots,{n\brace k}\) 。
补充内容:
斯特林数原本用于描述阶乘幂和幂之间的系数关系。第一类斯特林数 \(\begin{bmatrix}n\\k\end{bmatrix}\) 用于描述 \(x^{\underline{n}}\) 展开中 \(x^k\) 的系数,第二类 \(n\brace k\) 用于描述 \(x^n\) 展开中 \(x^{\underline{k}}\) 的系数。以此,幂和阶乘幂就可以很方便地进行转换。
因此可以得到关系式:
\[ x^{\underline{n}}=\sum_{k=0}^n\begin{bmatrix}n\\k\end{bmatrix} x^k\\ x^n=\sum_{k=0}^n{n\brace k} x^{\underline k} \]
当然,两种数都有其对应的组合含义。
1001
不难想到,可以直接枚举有球的盒子的数量:
补充说明:
当 \(r=n\) 的时候,问题就变成了,对于大小为 \(n\) 的集合 \(S\) ,将它划分成任意多个非空子集的方案数是多少?
专门有一个数列 \(\{b_n\}\) 来描述它。这类数就叫 " 贝尔数 " 。
简单推导(考虑第 \(n\) 个元素所在集合大小)可以得出贝尔数的转移:
\[\begin{aligned} b_n&= \begin{cases} 1&n=0\\ \sum_{k=1}^{n} \binom{n-1}{k-1}b_{n-k}& otherwise \end{cases}\\ b_n&=\sum_{k=0}^n{n\brace k} \end{aligned} \]
可以定义 \(B(x)\) 为贝尔数的指数型生成函数,那么就有 \(B(x)=e^{e^x-1}\) 。具体推导可以参考 洛谷日报 等资料。
1010*
同样可以枚举球的数量:
你发现这个式子仍然可以使用 NTT 批量计算。甚至此情况的答案可以直接写成生成函数形式。
1011*
同样可以枚举球和空盒子的数量:
00--
球相同、盒相同问题求解的基本原理是动态规划。
0001
不难发现,此时我们可以直接用每个盒子的球数组成的序列来描述一种方案。
那么我们只枚举单调不减的序列就好了,也就是说,原问题的等价于求自然数序列的数量:
这里有一个很常见的转化:枚举单调不降序列,就相当于枚举全是 1 的后缀的和。
具体来说,我们可以定义
那么一个单调不降的序列就必然可以拆分成多个 \(s\) 的对应位的和。比如 \(n=4\) 时, \(\{1\ 2\ 3\ 3\}=s_1+s_2+s_3\) 。
于是不难想到一个完全背包:
\(g(i,j)\):在考虑完 \(s_1\sim s_j\) 后,所有后缀的和为 \(i\) 的方案数。
可以得到转移为:
此时的答案就是 \(g(n,r)\) 。
0000
此时盒子不能为空,我们可以直接给每个盒子分配一个球。当 \(n<r\) 时,答案是 \(0\) 。当 \(n\ge r\) 时,答案就是 \(g(n-r,r)\) 。
0011*
球没有区别,因此可以直接枚举数量:
0010*
基本同上:
总结
盒子放球问题虽然模型简单,但是你可以发现,在 16 种问题中,我们用了 4 种主要的思路:乘法原理、隔板法、斯特林数、动态规划,以及一些常见的技巧,比如容斥。每种主要思路下, 4 个子问题的方法不尽相同。不同主要思路下,处理子问题的限制的方法各自有些相似。
所以说,深入学习盒子放球,对于学习计数是比较有意义的。它的确可以帮助你熟悉一些基础的计数方法。