目录
本篇博客中多项式浓度较低,请放心食用。
基本原理
分类加法原理
分类加法原理:做一件事有 \(n\) 类互斥的方式,而第 \(i\) 类方式具体有 \(c_i\) 种方案。那么总方案数为:
\[\sum_{i=1}^nc_i \]
分类加法原理的核心在于互斥二字。事实上,在组合数学中符号 \(+\) 本身就带有互斥的含义。
分步乘法原理
分类加法原理:做一件事有 \(n\) 步,而第 \(i\) 步具体有 \(c_i\) 种方案。那么总方案数为:
\[\prod_{i=1}^nc_i \]
这启示我们在组合数学中,符号 \(\times\) 带有分步的意义。
事实上,乘法原理还有一种带权的形式(自己认为的):
分步乘法原理的带权形式:做一件事有 \(n\) 步,第 \(i\) 步有 \(c_i\) 种方案,而选择其中第 \(j\) 种方案有 \(a_{i,j}\) 的收益。定义一个方案的收益是每一步的收益乘积,那么所有方案的收益之和是:
\[\prod_{i=1}^n(\sum_{i=1}^{c_i}a_{i,j}) \]
注意到每一步我们都用加法“连接”起各种法案的贡献,这是利用了加法的互斥原理:即第 \(i\) 步只能选择给出的 \(c_i\) 种方案中的一种。
这里还可以有一个有趣的讨论:如果方案的收益定义为每一步的收益之和该如何解决呢?有至少两种方法。其中一种我们后面再叙述,这里介绍另一种:
首先发现该问题可以分为若干步,第 \(i\) 步是从 \(c_i\) 种方案中选择一种。于是运用乘法原理将每一步链接起来。而 \(c_i\) 种方案是互斥的,所以应该用加法原理链接。然而怎样才能使得贡献是和呢?考虑到
因此答案就是:
然而仅凭基本原理我们能够解决的问题依然是很有限的,于是就要引入后面的东西了。
动态规划
这里“动态规划”的说法并不是很严谨,但是确实和动态规划中将大问题化为类似的子问题这一思想非常类似。在这部分中,基本原理仍然是十分重要的。接下来,我们来看几个例子:
一个有 \(n\) 阶台阶的楼梯,你要从地面开始走到顶部。每次你可以选择走 \(1\) 阶或者走 \(2\) 阶,问有多少种走法。
令 \(f_n\) 表示走 \(n\) 阶台阶的方案数。考虑最后一次是走 \(1\) 阶还是走 \(2\) 阶。显然这两种情况是互斥的,可以用加法链接起来,于是就有:
递推即可。
有 \(n\) 个带标号元素排成一个环。现在要用 \(c\) 种颜色给它们进行染色。要求任意相邻的元素染的颜色不同。问有多少种染色方案。
令 \(f_n\) 表示 \(n\) 个元素的染色方案数。注意到如果是链就非常好做,答案就是 \(c(c-1)^{n-1}\) 种,即用乘法原理链接,要和上一个的颜色不同。环的难点在于填染色一个元素时不清楚和它相邻的两个元素颜色是否相同。对这一点进行分类讨论即可。考虑 \(n-1\) 号元素和 \(1\) 号元素,如果它们颜色不同,方案数就是 \((c-2)f_{n-1}\) ;如果颜色相同,方案数则是 \((c-1)f_{n-2}\) 。这两种情况显然互斥,于是有:
错排问题:有多少长度为 \(n\) 的排列 \(p\) 满足 \(\forall i\in[1,n],p_i\not=i\) 。
设 \(f_n\) 表示 \(n\) 对应的答案。
对所有 \(i\) 我们建边 \(i\to p_i\) ,那么就能将排列变成若干环。题中的要求等价于不存在大小为 \(1\) 的环。考虑 \(n\) 的出边是 \(t\) ,有 \(n-1\) 种情况(除 \(n\) 以外都可行)且互斥。再考虑 \(t\) 的出边。如果它指向 \(n\) ,那么 \(n,t\) 形成一个二元环,方案数就是 \(f_{n-2}\) 。否则,我们可以直接删去 \(n\) ,然后将原来指向 \(n\) 的点指向 \(t\) ,此时该环大小仍然大于 \(1\) ,仍然是合法的。方案数是 \(f_{n-1}\) 。于是有:
借助动态规划,我们可以解决很多问题,但是往往都比较繁琐。那么是否存在一些简洁的解法呢?
特殊的数
这些”特殊的数“事实上可以看作一些模块,不少问题都会涉及到它们,可以很方便地随时调用。
组合数(二项式系数)
定义
\(\dbinom nm\) 表示从 \(n\) 个带标号元素中选出 \(m\) 个元素的方案数。
称 \(n\) 为上指标, \(m\) 为下指标。
最重要的10个二项式系数恒等式
定义式。通过该定义式可以将上指标拓展到实数。
对称恒等式。注意需要满足上指标 \(\ge0\) 这一条件。
吸收恒等式。
加法恒等式。有关组合数的递推/归纳问题都会用到该恒等式。
上指标反转。用于处理上指标 \(<0\) 的情况。
三项式版恒等式。严格包含吸收恒等式。在推导中通过该柿子(正用/倒用)可以有效地分离变量,从而大大简化运算。
二项式定理。可以将 \(k\) 拓展到实数从而变成“广义二项式定理”。
平行求和法。
上指标求和法。两种求和法在题目中都有应用。
范德蒙德卷积公式。在处理组合数乘积求和问题时很有帮助。
上面这些公式都是在已经得到最原始的“柿子”后推导才使用的。于是我们后面的重点主要是如何得到计算式。
经典例题
从 \((0,0)\) 出发,每次只能向上/向右走一个单位长度。问走到 \((n,m)\) 有多少种走法。
我们将向上看作 \(1\) ,向右看作 \(0\) ,那么就将一种走法和一个 \(01\) 序列建立了一一映射。观察 \(01\) 序列性质:长度为 \(n+m\) ;其中恰好有 \(n\) 个 \(0\) 。于是方案数就是:
将 \(n\) 个不带标号的小球放入 \(m\) 个带标号的盒子中。其中有 \(k\) 个盒子可以为空, \(n-k\) 个盒子至少放一个。问有多少种方案。
经典隔板法。先强制那 \(k\) 个盒子必选,即先钦定它们有 \(-1\) 个小球。此时我们有 \(n+k\) 个小球,有 \(n+k-1\) 个空隙,需要用 \(m-1\) 个隔板将其分到 \(m\) 个盒子中,因此方案数就是:
有 \(n\) 个元素排成一排,要求从其中选出 \(m\) 个元素,使得任意两个元素都不相邻。问有多少种选法。
和前面的隔板法类似。先取出要选的 \(m\) 个元素,然后再将剩下的 \(n-m\) 个元素放入其中。要求头尾的空隙可以不放,但是中间的空隙必须放。放好了后从左到右依次标号就是一种选取方案了。因此答案是:
\(n\) 个点的联通图个数有多少。
该问题需要结合前面的思想。令 \(f_n\) 表示答案。直接做没什么思路,于是正难则反,用总法案数减去不联通的方案数。总方案数是平凡的。对于不联通的情况,我们枚举 \(n\) 号点所在的连通块大小,剩下的随意连,于是就有:
这里直接给出结论:满足条件当且仅当初始序列满足 \(a_i=i\) ,然后选择\(⌊\dfrac n2⌋\) 个位置 \(−x\) ,剩下位置 \(+x\) ,其中 \(x\) 为任意非零整数。
先考虑 \(x\ge 0\) 的情况。现在的难点在于每个点最多能加/减的数是不同的。然而我们注意到这样一条性质:越靠后的数最多能加的数单调递减,而最多能减的数则单调递增。这其实我们枚举最靠前的减的位置 \(i\) 和最靠后的加的位置 \(j\) ,那么答案就是(令 \(t=⌊\dfrac n2⌋\) ):
分类讨论将 \(\min\) 拆开,之后就是上指标求和了。
对于 \(x<0\) ,做法是类似的。
将 \(n\) 个带标号的小球放入 \(m\) 个带标号集合中,要求第 \(i\) 个集合恰好放 \(a_i\) 个小球,满足 \(\sum_ia_i=n\) 。问有多少种放置方法。
我们一个集合一个集合地进行考虑,那么答案事实上是:
最后面的符号代表多项式系数。
有关多项式系数的还有多项式定理,即:
斯特林数
基础知识直接见blog。
题目中观察到和其组合意义相同的东西直接套用即可。
推柿子时可以通过斯特林数进行下降幂、普通幂和上升幂之间的相互转化。注意组合数的定义式中包含下降幂,因此转化为下降幂后可以用前面的公式推导。
容斥与反演
大部分时候我们第一时间想到的计数方式都是直接对合法方案进行不重且不漏地计数。然而有些时候直接这样做是极为困难的。但是我们发现这只是我们想要的结果,在中间的计算过程中计算多次或者统计到不合法的方案都是可以接受的,只要最后结果满足条件就行。
容斥原理
为什么是正确的呢?考虑任何一个被恰好 \(k(k>0)\) 个集合包含的元素,它会被计算:
从而证明了其正确性。
事实上,所有容斥的正确性都是如此证明的,即任何一种合法方案一定恰好被计算一次,所有非法方案都不会被计算。
容斥原理有两种用法:
- 对条件进行容斥:例如要计算同时满足条件 \(A,B\) 的方案数,我们可以先计算满足 \(A\) 的,再减去满足 \(A\) 但不满足 \(B\) 的。又或者我们要计算满足条件 \(A,B\) 中的任意一个的方案数,那么我们可以先计算满足 \(A\) 的方案数与满足 \(B\) 的方案数,之后再减去 \(A,B\) 同时满足的方案数。总之,这里的容斥方法不用那么死板。
- 对结果进行容斥:如果某个计数问题的答案是一组数,对其中每一个数都存在限制时,我们可以先算出忽略限制的答案,然后钦定其中任意一个数不满足限制,减去对应的答案,再把有两个不满足限制的数的情况答案加回来,以此类推。
卡农:在集合 \(S=\{1,2,3,\cdots,n\}\) 中,选出 \(m\) 个不带标号的互不相同的非空子集,要求每个数的出现次数都是偶数。
首先将“不带标号”变为“带标号”,最后将答案除以 \(m!\) 即可。
令 \(f_i\) 表示选择 \(i\) 个集合时的答案。先满足每个数的出现次数都是偶数这一条件。如果前 \(i-1\) 个集合已经确定,那么第 \(i\) 个集合也确定了,方案数为 \((2^n-1)^{\underline{i-1}}\) 。
此时前 \(i-1\) 个集合满足了互不相同且非空。考虑第 \(i\) 个集合。如果它为空,那么对应于 \(f_{i-1}\) 的情况;如果它和前面某个 \(j\) 相同,那么将 \(i,j\) 全部删除后仍然合法,对应于 \(f_{i-2}\) ,于是有 \((i-1)(2^n-1-(i-2))f_{i-2}\) 种方案。有递推:
直接模拟该柿子即可。
将 \(n\) 个小球放入 \(m\) 个盒子中,要求每个盒子内的小球数都不超过 \(k\) 个。求方案数。
每次钦定一些盒子的小球数超过 \(k\) 个,然后直接套用集合容斥的柿子(这里因为所有盒子的限制都是相同的,所以可以直接枚举钦定的个数后统一计算):
二项式反演
对着柿子讲完全无法发现其巨大优势。直接来看看例题。
已经没有什么好害怕的了:给出两个长度都是 \(n\) 的序列 \(a,b\) ,询问有多少种长为 \(n\) 的排列 \(p\) 满足恰好有 \(t\) 个 \(i\) 使得 \(a_i>b_{p_i}\) 。
“恰好 \(t\) 个”非常难做,我们先考虑求出钦定了 \(t\) 个,其他随便乱选的答案 \(g_t\) 。
这个可以dp求出。将 \(a\) 从小到大排序,令 \(f_{i,j}\) 表示考虑了前 \(i\) 个 \(a\) ,其中已经钦定了 \(j\) 个 \(a>b\) 关系的方案数。有转移:
其中 \(d_i\) 表示 \(<a_i\) 的 \(b\) 数量。
然后就有 \(g_t=f_{n,t}(n-t)!\) 。
设最终答案是 \(h_t\) 。我们钦定 \(s(s\le t)\) 个时会计算到统计这种情况 \(\dbinom ts\) 次,因此有柿子:
套用上面的公式就能反算出 \(h\) 。
总结一下二项式反演的作用:将“恰好 \(n\) 个”这种困难问题转化为"钦定 \(n\) 个后随意选择"这种相对简单的问题。
莫比乌斯反演
斯特林反演
见此。
\(\min-\max\) 容斥
其中 \(E(x)\) 表示变量 \(x\) 在期望意义下的值。当然不在期望意义下上面的柿子也是正确的,但是这时候也没有必要这么麻烦地去求最值了。
这类问题多是考察找到 \(\min(S),\max(S)\) 的对应意义。
HAOI2015 按位或:刚开始你有一个数字 \(0\) ,每一秒钟你会随机选择一个 \([0,2^n −1]\) 的数字,与你手上的数字进行或操作。选择数字 \(i\) 的概率是 \(p_i\) 。保证 \(0 ≤ p_i ≤ 1,\sum_ip_i=1\) 。问期望多少秒后,你手上的数字变成 \(2^n − 1\) 。
我们令 \(t_i\) 表示二进制位中第 \(i\) 位第一次变成 \(1\) 的时间,那么我们事实上要求的是 \(E(\max(t_1,t_2,\cdots,t_n))\) 。
使用 \(\min-\max\) 容斥,问题转化为对所有 \(T\in\{1,2,\cdots,n\}\) 求 \(E(\min(T))\) 。由于我们有引理:对于某个事件,如果其发生的概率为 \(P\) ,那么期望意义下重复 \(\dfrac 1P\) 次后就会发生一次该事件。因此有:
后面的东西不是本章重点,因此不再赘述。
集合容斥
一些比较典的容斥
1
如果要求恰好 \(k\) 个的答案,可以考虑用 \(\ge k\) 的答案减去 \(\ge k+1\) 的答案或者用 \(\le k\) 的答案减去 \(\le k-1\) 的答案。通过放宽限制一定程度上使问题变得简单。
2
如果要求满足条件 \(A\) 的答案,可以用总方案数减去不满足 \(A\) 的方案数。例如Emiya 家今天的饭中要求主要食材至多在一半的菜中被使用就暗示我们用总方案数减去存在某个超过一半的答案。
3
如果要求极差不大于 \(k\) 的答案,可以枚举 \(t\) 然后计算最大值 \(\le t+k\) 的方案数,再求和此时极差恰好为 \(p\) 的方案会被计算 \(k-p+1\) 次。于是我们令 \(k\gets k-1\) ,再按照上述方法计算一遍再减去,合法方案就会恰好被计算 \((k-p+1)-(k-1-p+1)=1\) 次了。
4
从 \((0,0)\) 出发,每次只能向上/向右走一个单位长度。要求不能越过 \(x-y=0\) 这条直线。问走到 \((n,n)\) 有多少种走法。
总方案数在前面组合数的部分已经讨论过了,答案是 \(\dbinom {2n}n\) 。现在我们只需考虑减去不合法的方案数了。
“越过”是不好处理的。我们将限制变为不能触碰 \(x-y+1=0\) 这条直线。考虑一种不合法的走法,然后找到该走法和 \(x-y+1=0\) 的第一个交点,之后将后面的路径按照 \(x-y+1=0\) 进行轴对称,那么此时该走法对应于一条从 \((0,0)\) 到 \((n-1,n+1)\) 的路径,方案数是 \(\dbinom{2n}{n-1}\) 。
于是方案数就是 \(\dbinom{2n}n-\dbinom{2n}{n-1}\) 。这就是卡特兰数。
拓展1.
从 \((0,0)\) 出发,每次只能向上/向右走一个单位长度。要求不能越过 \(Ax-y+B=0\) 这条直线。问走到 \((n,An+B)\) 有多少种走法。
直接给出结论:答案是 \(\dbinom{(A+1)n+B}n-A\dbinom {(A+1)n+B}{n-1}\) 。
拓展2.
从 \((0,0)\) 出发,每次只能向上/向右走一个单位长度。要求不能越过 \(y=x+p,y=x-q(p,q\in\mathbb N)\) 这两条直线。问走到 \((n,m)\) 有多少种走法。
见JLOI2015 骗我呢题解后半部分。
拆贡献在计数中的应用
拆贡献在OI中向来是非常重要的思想。比如笔者在某次考完模拟赛后问某同学某道题该如何解决时,他说:“拆贡献后随便做做就完了。”
拆贡献本质是换个角度看问题的一种方式。
做一件事有 \(n\) 步,第 \(i\) 步有 \(c_i\) 种方案,而选择其中第 \(j\) 种方案有 \(a_{i,j}\) 的收益。定义一个方案的收益是每一步的收益之和。求所有方案的收益之和是。
枚举每个 \(a_{i,j}\) ,观察发现其贡献次数就是除了第 \(i\) 步以外的方案数。因此答案就是:
转化:对于每个起点分别求路径长度最后求和转化为求每一时刻未走出边界的起点个数再求和。
给出一个 \(n\) 行 \(m\) 列的矩阵 \(a\) ,我们定义一次变换为:
- 新建一个矩阵 \(a'\) 。
- 令 \(a'_{i,j}=a_{i,j-1}+a_{i-1,j}\)
\(a\gets a'\)
现在有若干次询问,每次询问进行 \(k\) 次变换后 \(a_{p,q}\) 的值是多少。
\(n,m,k\le 500\)
转化:只有满足 \(i\le p,j\le q,|i-p|+|j-q|=k\) 的位置才会给答案贡献 \(\dbinom{k}{|i-p|}\) 次。于是枚举这些位置统计贡献即可。
总结下,“拆贡献”其实是将“求一组数在所有情况下的和的和”转化为“求每个数在所有情况下会贡献多少次,然后求和”。
组合意义
计数中怎么能少的了组合意义呢!(震声)
对于一个长度为 \(n\) 的排列 \(a\) ,定义其权值为 \(q^{\sum_i[a_i=i]}\) 。问如果满足 \(a\) 取遍所有情况时的权值和。
\(n\le 10^7\)
思路自然是枚举 \(a_i=i\) 恰好为 \(i\) 个的方案数然后乘上 \(q^i\) ,最后求和。可以发现方案数就是 \(\binom nid_{n-i}\) ,其中 \(d_i\) 表示长度为 \(i\) 的错排数,可以递推。
然而还有一种更妙的想法。可以想到使用二项式反演将“恰好”变为”钦定“,然而复杂度太高。那能否不反演呢?我们不再统计方案数,而是将其和权值加在一起考虑。一个权值恰为 \(q^t\) 的排列会在钦定 \(s\) 个位置时被计算 \(\dbinom ts\) 次,这个东西让我们联想到二项式定理。考虑到:
于是我们只需要将钦定 \(s\) 个位置的权值变为 \((q-1)^s\) 就能计算出正确答案了。于是答案就是:
给出一棵 \(n\) 个点的树。定义一个森林的权值为 \(n^k\prod_is_i\) ,其中 \(k\) 代表连通块个数, \(s\) 代表连通块大小。要求对于 \(2^{n-1}\) 种断边方案求权值和。\(n\le 10^7\)
我们可以直接暴力dp: \(f_{u,i,j}\) 表示子树 \(u\) ,当前已经断了 \(i\) 条边(据此可以指导连通块个数),当前 \(u\) 所在的连通块大小为 \(j\) 时的答案。复杂度非常爆炸。
观察组合意义:每多一个连通块,代价就乘 \(n\) ,可以直接在转移时体现,因此第二维可以省去。而 \(s_i\) 则对应着在连通块中任选一个点作为关键点的方案数。因此dp状态可以优化为: \(f_{u,0/1}\) 表示子树 \(u\) ,当前 \(u\) 所在连通块否/是选择了关键点时的答案。合并进一棵子树时考虑边断/不断即可。
然后你就可以去做WC2019 数树了。
将 \(n\) 个小球放入 \(k\) 个带标号盒子中(盒子可以为空),定义一种放法的权值是每个盒子的放球个数的 \(t\) 次方。求所有放法的权值和。
首先使用第二类斯特林数将常规幂转化为组合数,即 \(x^t=\sum_s {t\brace s}s!\binom xs\) 。前面的系数可以暂时不用管,现在只关心如何求最后的那个组合数。注意到组合意义,即每 \(s\) 个球在同一个盒子里就会产生 \(1\) 的贡献。因此我们可以列出柿子:
直接带入计算便可得到答案。