二项式反演
二项式反演
(写这么个玩意也不容易,如果发现有错请及时联系我qwq)
1. 反演的定义
演绎推理是我们在数学中经常遇到的方法。对于数列来说,通过原数列计算出新数列叫作演绎,而通过计算出的数列反推出原数列则被称为反演。
举个例子,假设有两个数列 \(f(x)\) 和 \(g(x)\),\(f(x)\) 为原数列,\(g(x)\) 为新数列。我们从 \(f(x)\) 推出 \(g(x)\) 的过程就叫做演绎,而利用 \(g(x)\) 反推出 \(f(x)\)的过程就叫做反演。
一般来说,有了两个数列的相互关系,我们才能相互推算。在一些特定的情况下,相互关系会有一些特殊的性质,人们将重要的、常见的相互关系命名,并深入研究其性质,如二项式反演、莫比乌斯反演、单位根反演、子集反演等。
再举个例子,我们假设 \(g(x)\) 与 \(f(x)\) 满足:
我们可以利用它们的关系式,从 \(f(x)\) 推到 \(g(x)\),也可以通过解 \(n\) 元一次方程组,从 \(g(x)\) 推到 \(f(x)\)。当然,这个关系式的反演过程只需要简单地进行解方程组,所以并没有特别的名字。
2. 通过容斥原理推导二项式反演
不会容斥原理的可以来看我的另一篇博客
我们设全集 \(U = \{S_1, S_2, \dots, S_{n - 1}, S_n \}\) 中的任意 \(i\) 个元素的并集大小相等,任意 \(i\) 个元素的交集大小也相等。
设 \(g(n)\) 代表任意 \(n\) 个集合的交集,\(f(n)\) 代表任意 \(n\) 个集合的补集的交集。特别地,\(g(0) = f(0) = |U|\)
那么我们就能得到下面两条容斥式子:
所以我们得到了优美的 一点都不优美的 二项式反演式子:
3. 二项式反演的常用形式
形式一
已知公式:
我们假设 \(h(n) = (-1)^n f(n)\),则有:
即
而对于整数 \(i\),\(n - i = n + i - 2 \cdot i\),所以在对 \(2\) 取模的意义下,有 \(n + i \equiv n - i\ ( mod\ 2)\)。
所以有
即常见的:
这也就是第一个常用的形式,不过这里 \(g(x)\) 与 \(f(x)\) 的定义视情况而定。
形式二
先给出形式:
将右式代入左式,则
等式两边恒等,故恒成立。
4. 二项式反演在题目中的应用
4.1 几个经典问题
4.1.1 全错位排列问题
错位就是原来在某一位置上的数不能在这个位置上,或者说 \(a_i \ne i\)
全排列就不再解释了
对于这个问题,我们可以定义 \(g(x)\) 表示 \(n\) 个数中,至多有 \(x\) 个 \(a_i \ne i\) 的总方案数。\(f(x)\) 表示 \(x\) 个数的全错位排列的方案数。
所以有:
从 \(g(x)\) 的定义来看,有
所以我们可以用二项式反演得到 \(f(n)\) :
在求和式中,把 \(n!\) 提出来,再用 \(i\) 代换 \(n - i\),式子不变,得到
这也就是所谓的全错位排列公式。
4.1.2 第一类斯特林数
想了解斯特林数的可以看看我的另一篇博客,这里只是大概描述一下斯特林数所解决的基本问题。
有 \(n\) 个不同的球放入 \(m\) 个不同的盒子,要求每个盒子非空,球有多少种方案数。
这里的限制是“非空”,那我们就从这里入手,定义 \(g(m)\) 表示 \(n\) 个不同的球放入 \(m\) 个不同的盒子,至多有 \(m\) 个盒子非空的方案数,\(f(m)\) 表示 \(n\) 个不同的球放入 \(m\) 个不同的盒子,恰好有 \(m\) 个盒子非空的方案数。
易得:
二项式反演后得:
4.1.3 第二类斯特林数
一样,也在我那篇博客里有详细介绍,这里只是粗略说下所解决的基本问题。
有 \(n\) 个不同的球放入 \(m\) 个相同的盒子,要求每个盒子非空,球有多少种方案数。
其实它与第一类斯特林数就不同在了盒子是否相同,所以我们的定义与推导过程基本不变,只不过最终的式子再除以 \(m!\) 即可
4.1.3 计数问题
重点就在于怎么找到限制条件 \(/\) 性质,有了限制条件 \(/\) 性质,就能找到 \(g(x)\) 与 \(f(x)\) 的含义,也就能通过二项式反演轻松解决掉问题。
4.1.3.1 题目大意
给定 \(n\),并给定 \(a_1, a_2, \dots, a_n\) 以及 \(b_1, b_2, \dots, b_n\),要求两两配对使得 \(a_i > b_j\) 的对数减去 \(a_i < b_j\) 的对数等于 \(k\) 。(\(0 \le k \le n \le 2000, a, b\) 中无相同元素)
4.1.3.2 分析
比较明显的计数问题。既然明确告诉我们要求恰好有 \(k\) 个,那我们就可以很容易想到我们二项式反演。
4.1.3.3 题解
设有 \(x\) 对 \(a, b\) 满足 \(a > b\),那么有 \(n - x\) 对 \(a, b\) 满足 \(a < b\),也就意味着我们要让 \(x - (n - x) = k\) 即 \(\displaystyle x = \frac{n + k}{2}\)。
现在我们要考虑怎么求恰好有 \(x\) 个 \(a > b\),自然过渡到用二项式反演解决。
设 \(g(x)\) 表示至少有 \(x\) 对 \(a > b\) 的方案数,\(f(x)\) 表示恰好有 \(x\) 对 \(a > b\) 的方案数。
那么有:
那我们现在就要去考虑如何计算 \(g(x)\)。
我们先将 \(a\) 和 \(b\) 分别从小到大排序。设 \(r(i)\) 表示比 \(a_i\) 小的 \(b\) 的个数,\(F(i, j)\) 表示前 \(i\) 个 \(a\) 中(排序后)恰好有 \(j\) 对 \(a > b\) 的方案数。可以列出状态转移方程:
而 \(g(i)\) 就等于 \((n - i)! \cdot F(n, i)\)
有了这些,\(f(\frac{n + k}{2})\) 就很好求了。
4.1.3.4 代码
点击查看代码
#include<bits/stdc++.h>
#define M 2007
#define mod 1000000009
#define int long long //我习惯不好,别学我
using namespace std;
int n, k, x, ans;
int a[M], b[M], F[M][M], r[M], fac[M], g[M], inv[M];
inline int quick_pow(int base, int p) {
int res = 1;
while(p) {
if(p & 1)
res = res * base % mod;
base = base * base % mod;
p >>= 1;
}
return res;
}
inline int C(int a, int b) {return fac[a] * inv[b] % mod * inv[a - b] % mod;}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i = 2; i <= n; ++ i) {
fac[i] = fac[i - 1] * i % mod;
inv[i] = quick_pow(fac[i], mod - 2);
}
x = (n + k) >> 1;
for(int i = 1; i <= n; ++ i)
cin >> a[i];
for(int i = 1; i <= n; ++ i)
cin >> b[i];
stable_sort(a + 1, a + 1 + n);
stable_sort(b + 1, b + 1 + n);
for(int i = 1; i <= n; ++ i)
r[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b - 1;
F[0][0] = 1;
for(int i = 1; i <= n; ++ i) {
F[i][0] = 1;
for(int j = 1; j <= i; ++ j)
F[i][j] = (F[i - 1][j] + (r[i] - j + 1) * F[i - 1][j - 1] % mod) % mod;
}
for(int i = x; i <= n; ++ i)
g[i] = F[n][i] * fac[n - i] % mod;
for(int i = x; i <= n; ++ i) {
if((i - x) & 1)
ans = (ans - C(i, x) * g[i] % mod + mod) % mod;
else
ans = (ans + C(i, x) * g[i] % mod) % mod;
}
cout << ans;
}
4.2 方法总结
总的来说,把握好至少 \(/\) 至多与恰好的关系是最重要的。
4.2.1 至少与恰好
假设共有 \(n\) 种不同的性质,\(g(x)\) 表示从有若干个元素的集合中,选出若干个至少有 \(x\) 种不同性质的元素的集合总方案数,\(f(x)\) 表示从有若干个元素的集合中,选出若干个恰好有 \(x\) 种不同性质的元素的集合方案数。
那么根据我们刚才的结论,有:
4.2.1 至多与恰好
假设共有 \(n\) 种不同的性质,\(g(x)\) 表示从有若干个元素的集合中,选出若干个至多有 \(x\) 种不同性质的元素的集合总方案数,\(f(x)\) 表示从有若干个元素的集合中,选出若干个恰好有 \(x\) 种不同性质的元素的集合方案数。
那么根据我们刚才的结论,有:
5. 多元二项式反演 \(/\) 高维二项式反演
(个人感觉挺难的)
5.1 结论
设有 \(m\) 个非负整数 \(n_1, n_2, \dots, n_m\)。假设 \(f(n_1, n_2, \dots, n_m)\) 及 \(g(n_1, n_2, \dots,n_m)\) 都是整数,且:
那么有:
注:
\( \displaystyle \sum_{k_i = 0}^{n_i} = \begin{matrix} \underbrace{\sum_{k_1 = 0}^{n_1} \dots \sum_{k_i = 0}^{n_i} \dots \sum_{k_m = 0}^{n_m}}\\共m个\end{matrix} \)
5.2 证明
既然你已经看到这里了,说明你很强了,所以我接下来就不写那么细了
我们先来证明一个小东西 恶心人的东西,我们一会需要用到:
证明如下:
当 \(n = j\) 时,原式等于 \(1\)
当 \(n \not= j\) 时,原式利用二项式定理可以继续化简:
得证。
我们再继续证我们最初要证的东西:
利用刚刚证明的引理,我们可以发现只有当 \(t_1 = n_1, t_2 = n_2, \dots, t_m = n_m\) 时,\(\displaystyle \sum_{k_i=t_i}^{n_i}\prod_{i=1}^m(-1)^{n_i-k_i}\dbinom{n_i}{k_i}\dbinom{k_i}{t_i} f(t_1,t_2,\cdots,t_m)\) 的值才不为 \(0\),为 \(f(n_1, n_2, \dots, n_m)\)。
所以原式等于 \(f(n_1, n_2, \dots, n_m)\),得证。
5.3 例题
一道简单的 恶心的 二元 \(/\) 二维二项式反演
式子给你,我就不写题解了(你自己写着玩去吧,我懒)
6. 总结 \(/\) 后记
二项式反演在很多问题中用处还是不小的,尤其是计数问题,很多都用到了二项式反演,有能力的话还是搞得明白一点比较好。
(呃呃呃,终于写完了,整个人都不好了)
(写这么个玩意也不容易,如果发现有错请及时联系我qwq)