二项式反演:从“至少”到“恰好”的组合计数转换利器

📅 2026/6/21 18:30:33
二项式反演:从“至少”到“恰好”的组合计数转换利器
1. 从“恰好”到“至少”二项式反演的核心思想做组合计数或者概率论的朋友肯定都遇到过这种场景题目要求你计算“恰好有k个元素满足某条件”的方案数但你吭哧吭哧算半天发现直接算“恰好”简直难如登天。反倒是算“至少有k个元素满足条件”的方案数思路清晰公式顺手。这时候一种强烈的直觉就会冒出来能不能用一堆“至少”的信息把那个求而不得的“恰好”给反推出来二项式反演就是解决这个问题的“数学魔法”。它不是什么高深莫测的新理论而是一套精巧的公式专门处理“至少/至多”与“恰好”这两类计数之间的转换关系。它的核心价值在于为我们提供了一条“曲线救国”的路径当你被“恰好”卡住时不妨先去看看“至少”是否好算最后再用反演公式“拧”回来。举个最生活化的例子。你想知道班上有恰好5个人喜欢篮球但直接调查“恰好”太难了。你可以先调查“至少喜欢篮球的人数”比如问“喜欢篮球的请举手”统计举手人数但这得到的是“至少1个”。这不够。更聪明的办法是利用容斥原理或者别的模型先算出“至少有1个”、“至少有2个”……“至少有n个”喜欢篮球的人数。然后二项式反演公式就能像一把钥匙帮你从这一串“至少”的数据中解出那个唯一的“恰好5个”的答案。所以理解二项式反演关键不在于死记硬背那两个公式而在于理解它背后的互补计数思想和容斥原理的精华。它告诉我们很多时候正难则反直接搞不定的“精确值”可以通过更容易计算的“带约束的累积值”来反向推导。接下来我们就一层层剥开它的外壳看看这枚“数学坚果”里到底藏着什么。2. 公式拆解两种经典形式及其内在联系二项式反演通常以两种对称的形式出现它们就像一枚硬币的两面解决着“至少”与“恰好”互化的问题。我们先用符号定义清楚。设我们有一个关于整数k的函数f(k)和g(k)。f(k)通常表示恰好有k个元素满足某种性质的方案数或概率、权值和等。这是我们最终想求的但往往很难直接计算。g(k)通常表示至少有k个元素满足某种性质的方案数。或者更一般地g(k)可以理解为先钦定k个元素满足性质其他元素任意时计算出的方案数。这类计数往往有更清晰的组合意义或更简单的计算方法。2.1 标准形式从“钦定”到“恰好”这是最常见、最符合直觉的形式。公式一如果对于所有n k 0有g(k) Σ_{ik}^{n} C(i, k) * f(i)那么我们可以反解出f(k)f(k) Σ_{ik}^{n} (-1)^{i-k} * C(i, k) * g(i)这个形式在说什么g(k) Σ_{ik}^{n} C(i, k) * f(i)这个等式是理解的关键。左边g(k)是“钦定k个满足条件”的方案数。右边怎么理解考虑所有恰好有i个元素满足条件的方案共f(i)种。在这些方案中任意选出k个满足条件的元素有C(i, k)种选法就构成了一种“钦定k个”的情况。由于i可以从k取到n因为至少要有k个才能选出k个所以对所有i求和就得到了g(k)。所以这个等式的组合意义非常直接“钦定k个”的方案数等于所有“恰好有i个”的方案中选出那k个的所有可能之和。那么反演公式f(k) Σ_{ik}^{n} (-1)^{i-k} * C(i, k) * g(i)就是它的逆运算。它通过带有正负交替符号(-1)^{i-k}的求和从“钦定”系列{g(i)}中筛出纯净的“恰好”f(k)。这里的(-1)^{i-k}是容斥原理的典型标志用于扣除那些“多钦定了”的部分。2.2 对称形式从“至多”或另一种视角的转换另一种常见的形式如下公式二如果对于所有0 k n有g(k) Σ_{i0}^{k} C(k, i) * f(i)那么有f(k) Σ_{i0}^{k} (-1)^{k-i} * C(k, i) * g(i)这个形式又如何理解这里g(k)的定义可能稍有不同。一种常见的解释是g(k)表示“至多有k个”元素满足性质的方案数。等式g(k) Σ_{i0}^{k} C(k, i) * f(i)可以理解为要构造一个“至多有k个满足”的方案我们可以先确定它实际上“恰好有i个”满足i k然后在全部n个位置中这i个满足条件的位置必然是那k个被允许的位置的子集。但更通用的理解是这是一种“从0到k”的累积计数与“恰好”计数之间的关系。反演公式同样通过容斥来分离出精确值。2.3 两种形式的联系与记忆技巧本质上两种形式是统一的只是求和上下限和组合数C的参数位置不同。它们都体现了二项式系数在联系不同粒度计数时的核心作用。一个实用的记忆方法看求和下标如果g(k)的求和是从ik到n公式一那么它对应的是“至少/钦定”到“恰好”的反演组合数是C(i, k)。看正负号指数反演公式中(-1)的指数是(i-k)或(k-i)它总是“求和下标 - 变量下标”的形式。在公式一中求和下标是i变量是k所以指数是i-k。这可以帮助你检查写出的公式是否正确。不必强行记忆两个公式。掌握第一种理解其推导过程第二种可以通过变量替换或对称性联想出来。更重要的是理解其推导基石——容斥原理。3. 原理深探容斥原理是如何推导出反演公式的二项式反演不是天上掉下来的公式它可以从更基础的容斥原理自然推导出来。理解这个推导过程不仅能让你彻底明白公式为什么长这样还能让你在遇到变形问题时有能力自己“造”出合适的反演公式。我们以公式一的推导为例。已知g(k) Σ_{ik}^{n} C(i, k) * f(i) 求证f(k) Σ_{ik}^{n} (-1)^{i-k} * C(i, k) * g(i)。证明思路代入法我们将已知的g(i)的表达式代入到待证明的公式右边目标是化简后得到左边的f(k)。开始代入右边 Σ_{ik}^{n} (-1)^{i-k} * C(i, k) * g(i)将g(i) Σ_{ji}^{n} C(j, i) * f(j)代入 右边 Σ_{ik}^{n} (-1)^{i-k} * C(i, k) * [ Σ_{ji}^{n} C(j, i) * f(j) ]交换求和顺序关键步骤这是一个双重求和。先对i求和再对j求和。我们可以交换求和顺序先固定j看哪些i会贡献给这个j。 观察下标i的范围是k i n在内部求和里j的范围是i j n。所以对于每个ji必须同时满足i k且i j。因此交换后 右边 Σ_{jk}^{n} f(j) * [ Σ_{ik}^{j} (-1)^{i-k} * C(i, k) * C(j, i) ]注意外层求和j从k开始因为如果j k内层i无法满足i k且i j。化简组合数乘积有恒等式C(j, i) * C(i, k) C(j, k) * C(j-k, i-k)。可以这样理解从j个元素中先选出i个再从这i个中选出k个等价于先从j个中直接选出k个再从剩下的j-k个中选出i-k个。 代入 内层求和 Σ_{ik}^{j} (-1)^{i-k} * C(j, k) * C(j-k, i-k)把与i无关的C(j, k)提到前面 C(j, k) * Σ_{ik}^{j} (-1)^{i-k} * C(j-k, i-k)变量替换与二项式定理令t i - k则当ik时t0当ij时tj-k。求和变为Σ_{t0}^{j-k} (-1)^{t} * C(j-k, t)根据二项式定理(1 - 1)^{j-k} Σ_{t0}^{j-k} C(j-k, t) * 1^{j-k-t} * (-1)^t Σ_{t0}^{j-k} (-1)^{t} * C(j-k, t)因此这个求和的结果就是(1 - 1)^{j-k}。得出最终结果当j - k 0时(1 - 1)^{j-k} 0。当j - k 0即j k时(1 - 1)^{0} 1。 所以内层求和Σ_{ik}^{j} ...只有在j k时才等于1其他情况都为0。代回整个表达式 右边 Σ_{jk}^{n} f(j) * [ C(j, k) * (当 jk 时为1否则为0) ]f(k) * C(k, k) * 1f(k)证毕。这个推导过程完美展示了容斥原理的精髓通过引入正负号交替的项来精确地抵消掉所有“不纯”的即j k的贡献只留下我们想要的j k的那一项。(-1)^{i-k}这个因子正是执行容斥操作的“开关”。实操心得很多同学觉得二项式反演公式复杂容易记混。其实你不需要死记硬背。只要理解g(k)是f(i)的带组合数系数的线性组合即g A * f其中矩阵A的元素是C(i, k)那么反演公式就是求这个系数矩阵的逆矩阵f A^{-1} * g。而通过上面的推导可以看到这个逆矩阵的元素正好是(-1)^{i-k} C(i, k)。从线性代数的角度理解它就是一个上三角矩阵的求逆其规律性非常强。4. 实战演练三类经典应用场景剖析理论再美不如一例。下面我们通过三个由浅入深的经典问题来看看二项式反演是如何在实战中发挥威力的。我会详细展示如何定义f和g如何建立它们之间的关系式并最终利用反演公式求解。4.1 场景一错排问题Derangement问题n封信装入n个对应的信封全部装错的方案数D_n是多少这是二项式反演最经典的入门例题。直接计算“全错排”很难但计算“至少有k封信装对”却很容易。定义函数设f(k)为恰好有k封信装对的方案数。我们最终要求f(0)即全错排数D_n。设g(k)为钦定k封信装对其余n-k封信随意装可对可错的方案数。建立关系“钦定k封信装对”意味着我们先从n封信中选出这k封一定装对的信有C(n, k)种选法。对于剩下的n-k封信由于信封已经被那k封对的信占用了对应的位置所以它们只能在剩下的n-k个信封中进行随意排列方案数是(n-k)!。 因此g(k) C(n, k) * (n-k)! n! / k!。应用反演公式公式一根据定义g(k)是钦定k个它应该等于所有恰好有i个装对的方案中选出k个的组合数之和g(k) Σ_{ik}^{n} C(i, k) * f(i)。这正好符合我们公式一的前提条件。 因此我们可以反演f(k) Σ_{ik}^{n} (-1)^{i-k} * C(i, k) * g(i) Σ_{ik}^{n} (-1)^{i-k} * C(i, k) * (n! / i!)求解目标 f(0)令k 0D_n f(0) Σ_{i0}^{n} (-1)^{i-0} * C(i, 0) * (n! / i!) Σ_{i0}^{n} (-1)^{i} * (n! / i!)因为C(i, 0) 1。 最终得到错排公式D_n n! * Σ_{i0}^{n} (-1)^i / i!避坑技巧这里最容易出错的是g(k)的计算。一定要理解“钦定”和“恰好”的区别。“钦定k个装对”时剩下的n-k个是任意排列所以是(n-k)!。如果错误地认为剩下的是错排D_{n-k}那就又绕回原问题了无法建立简单关系。4.2 场景二染色问题至少出现某种颜色问题用m种颜色给n个格子染色要求每种颜色至少使用一次求方案数。直接计算“每种颜色至少一次”很麻烦因为约束条件太多。但计算“钦定某k种颜色不用”就简单多了。定义函数逆向思维设f(k)为恰好有k种颜色没有使用的方案数。我们最终要求的是f(0)。设g(k)为钦定k种颜色不用即这k种颜色禁止使用其他颜色随意用的方案数。建立关系钦定k种颜色不用那么可用的颜色只剩下m-k种。用这m-k种颜色给n个格子随意染色每个格子有(m-k)种选择所以方案数是(m-k)^n。 同时我们是从m种颜色中“钦定”出k种不用的有C(m, k)种钦定方法。 因此g(k) C(m, k) * (m-k)^n。应用反演公式同样g(k)是“钦定k种颜色不用”它等于所有“恰好有i种颜色没用”的方案中选出那k种颜色的组合数之和g(k) Σ_{ik}^{m} C(i, k) * f(i)。 应用公式一反演f(k) Σ_{ik}^{m} (-1)^{i-k} * C(i, k) * g(i) Σ_{ik}^{m} (-1)^{i-k} * C(i, k) * C(m, i) * (m-i)^n求解目标 f(0)令k0得到恰好0种颜色没用即每种颜色至少用一次的方案数f(0) Σ_{i0}^{m} (-1)^{i} * C(i, 0) * C(m, i) * (m-i)^n Σ_{i0}^{m} (-1)^{i} * C(m, i) * (m-i)^n注意C(i, 0)1并且C(m, i) * (m-i)^n就是g(i)。 这个公式就是经典的容斥原理公式。可以看到二项式反演优雅地导出了它。经验之谈在这个问题中定义f(k)为“恰好k种颜色没用”是关键的一步逆向思维。因为题目要求是“至少用一次”正向约束我们将其转化为对“没用”这个属性的计数反向约束从而让g(k)钦定k种不用变得极其容易计算。这是应用反演时非常重要的技巧将难算的“至少满足”转化为好算的“钦定不满足”。4.3 场景三子集问题与高维前缀和SOS DP这是二项式反演在算法竞赛尤其是状态压缩DP中的一个高级应用常用于计算子集相关的计数或求和问题被称为SOS DPSum Over Subsets Dynamic Programming或高维前缀和。问题模型有一个定义在集合通常用二进制位掩码表示上的函数F(mask)。我们想要求另一个函数G(mask)其中G(mask)定义为所有mask的子集sub的F(sub)之和。即G(mask) Σ_{sub ⊆ mask} F(sub)反过来如果已知所有的G(mask)如何求出所有的F(mask)建立反演模型把每个二进制位看作一个元素。mask表示一个元素集合。令f(mask)就是我们想求的原始函数F(mask)。令g(mask)定义为G(mask)即所有子集的和。对于固定的mask考虑它包含popcount(mask)个元素即二进制中1的个数。g(mask)是mask的所有子集sub的f(sub)之和。对于一个恰好有i个元素的子集sub即popcount(sub) i它会被多少个“超集”mask所包含呢答案是如果sub是mask的子集那么mask除了包含sub的所有元素还可以任意包含剩下的n - i个元素中的一部分。因此包含sub的mask的数量是2^{n-i}。但这不是我们这里的关系。我们需要换一个角度。固定一个大的集合maskg(mask)是它所有子集的和。这可以写成g(mask) Σ_{sub ⊆ mask} f(sub)我们可以按照子集sub与mask的差异来分类。设sub与mask相差k个元素即mask有而sub没有的元素个数。那么sub可以通过从mask中剔除这k个元素得到。剔除这k个元素有C(popcount(mask), k)种方式因为只能从mask中为1的位里剔除。 然而更直接的方法是注意到这个公式g(mask) Σ_{sub ⊆ mask} f(sub)本身就是二项式反演对称形式的集合版本。应用反演公式对称形式对于每个固定的mask考虑它的位数n。我们可以按位来思考。定义f(k)在某个“上下文”中恰好有k个属性满足的方案数类比。g(k)至多有k个属性满足的方案数。 在集合语境下“子集”关系对应着“至多”。mask的所有子集就是那些“属于mask的属性位为1至多全部拥有”的集合。 实际上有更精确的公式。已知g(mask) Σ_{sub ⊆ mask} f(sub)那么反演得到f(mask) Σ_{sub ⊆ mask} (-1)^{popcount(mask) - popcount(sub)} * g(sub)其中popcount(x)表示二进制表示中1的个数。(-1)^{popcount(mask) - popcount(sub)}就是(-1)^{k}其中k是mask比sub多出的元素个数。算法实现SOS DP已知g(mask)即高维前缀和求f(mask)即原函数的算法就是基于上述反演公式的快速实现时间复杂度为O(n * 2^n)其中n是位数。// 假设 g[mask] 已经计算好求 f[mask] for (int i 0; i n; i) { // 遍历每一位 for (int mask 0; mask (1 n); mask) { if (mask (1 i)) { // 如果mask的第i位是1 g[mask] - g[mask ^ (1 i)]; // 容斥减去不含第i位的子集的和 // 注意这里是在原g数组上直接操作最终g数组会变成f数组。 // 更标准的写法是用另一个数组f并写成f[mask] g[mask] - g[mask ^ (1i)] } } } // 循环结束后g[mask] 中存储的就是 f[mask]这个循环的过程正是在逐位进行容斥计算其本质就是执行了二项式反演。核心要点在这个场景中二项式反演揭示了高维前缀和与其逆变换之间的关系。g是f的子集和高维前缀和而反演公式则是通过容斥原理从g中恢复出f。SOS DP 是这个反演过程的高效算法实现。掌握这一点对于解决涉及子集卷积、快速莫比乌斯变换FMT等问题至关重要。5. 边界、陷阱与扩展思考二项式反演虽然强大但使用不当也会掉进坑里。下面总结几个常见的注意事项和易错点。5.1 定义陷阱“钦定” vs “至少”这是最核心的易错点。g(k)的定义必须是“钦定k个”而不是“至少k个”。“钦定k个”我们指定了具体的哪k个元素满足条件其余元素任意。计算时先组合数C(n, k)选出这k个再乘以剩余元素的任意安排方案。g(k)通常较大。“至少k个”不指定具体是哪k个只要满足条件的元素个数大于等于k就行。它等于所有“恰好i个”ik的方案数之和即Σ_{ik}^{n} f(i)。这通常不等于g(k)。错误示例在错排问题中如果错误地将g(k)定义为“至少有k封信装对”那么g(k) Σ_{ik}^{n} C(n, i) * D_{n-i}这个式子本身就复杂且递归无法形成我们需要的简洁线性关系g(k) Σ C(i,k)f(i)导致反演无法进行。避坑指南每次定义g(k)时在心里默念“我要先指定出k个来”。确保你的计算公式是基于“指定/钦定”的。5.2 求和范围与组合数下标公式中的求和范围ik到n以及组合数C(i, k)的下标顺序必须严格对应。在g(k) Σ_{ik}^{n} C(i, k) * f(i)中组合数是C(i, k)不是C(k, i)或C(n, i)。它的意义是在恰好有i个的方案中选出k个作为被钦定的。求和从ik开始是因为如果“恰好”的个数i小于钦定数k你根本无法选出k个来。检查你的关系式是否满足这个形式是应用反演公式的前提。5.3 符号与指数反演公式中的(-1)^{i-k}指数是i-k不要写成k-i或其他。这个符号是容斥原理的体现用于抵消多算的部分。在推导或记忆时可以联想从“大的、包含多的”g(i)中减去“多余的”部分来得到“精确的”f(k)因此指数是(大的 - 小的)。5.4 从二项式反演到其他反演二项式反演是组合数学中反演技巧的一个特例。它启发我们只要两个数列{f_n}和{g_n}通过一个系数矩阵其中包含组合数、幂函数等联系起来就可能存在一个逆变换。例如莫比乌斯反演可以看作是定义在整除偏序集上的“二项式反演”将g(n) Σ_{d|n} f(d)反演为f(n) Σ_{d|n} μ(d) * g(n/d)其中μ是莫比乌斯函数扮演了类似(-1)^k的容斥角色。斯特林反演联系了斯特林数与幂函数形式为g(n) Σ_{k0}^{n} S(n, k) f(k)与f(n) Σ_{k0}^{n} s(n, k) g(k)其中S和s分别是第二类和第一类斯特林数。理解二项式反演的容斥本质是通向这些更广义反演公式的桥梁。它们的核心思想一脉相承通过一种容易计算的、带有“过度计数”的变换g来求解难以直接计算的精确计数f再利用逆变换通常涉及容斥系数进行还原。6. 总结与个人心得走完这一趟二项式反演应该不再是一团神秘的符号了。它本质上是一个工具一个基于容斥原理的、专门处理“钦定”与“恰好”计数转换的工具。它的强大在于将复杂的“恰好”计数问题转化为一系列更容易建模和计算的“钦定”计数问题。我在多次使用中的体会是成功应用二项式反演的关键三步是精准定义明确f(k)是“恰好k个”g(k)是“钦定k个”。这是思维的起点也是最容易跑偏的地方。轻松建模花主要精力去构建g(k)的计算式。这个式子应该比直接求f(k)简单得多通常是一个清晰的组合模型如选k个位置剩下的任意排列。套公式与化简建立g(k) Σ C(i,k)f(i)的关系后自信地套用反演公式。最后的结果往往是一个带(-1)^i求和的式子这可能就是最终答案也可能需要你利用组合恒等式进一步化简。最后分享一个检查技巧用小型数据验证。比如在错排问题中令n3手工列出所有装信方案分别数出f(0), f(1), f(2), f(3)恰好装对数再计算g(0), g(1), g(2), g(3)钦定装对数验证g(k) Σ C(i,k)f(i)是否成立再验证反演公式是否能从g算回f。这个过程能极大地加深你对定义和公式的理解避免在抽象层面迷失。二项式反演就像一把瑞士军刀在组合计数的工具箱里可能不是最常用的但一旦遇到它擅长解决的问题——那些“恰好”令人头疼而“钦定”却唾手可得的问题——它就能干净利落地斩开乱麻。希望这篇长文能帮你把这把刀磨得更亮收入囊中。