【笔记】二项式反演
很多时候如果元素是等价的,那么容斥本质上就是 \(i=0\) 的二项式反演。【[ARC096E] Everything on It】
其实好像所谓广义容斥就是二项式定理(
1 反演常⽤形式
这里令 \(N\) 为总的 不同 的元素个数。
1.0 关于「钦定」的概念
对于 \(N\) 个元素,我们人为认定其中满足某些特殊性质(一般即为题目中最后要求的答案所满足的要求)的元素。
似乎可以认为钦定的本质就是 选择。
注意到,如果钦定的元素,与元素本身无关,而只与元素间关系有关(比如元素个数(一般是这个)、元素间大小关系)。对于两种不同的这样的钦定是可以在一定情况下是等价的。
(说的好玄乎,具体可以参见下面的例题((
1.1 二项式反演 1
\(g(n)\) 表示从 \(N\) 个不同元素 钦定/选至多 \(n\) 个元素形成特定结构的方案数;
\(f(n)\) 表示 恰好 使用 \(n\) 个不同元素(且这 \(n\) 个元素均是被钦定的)形成特定结构的总方案数。
若已知 \(f(n)\) 求 \(g(n)\),那么显然有:
若已知 \(g(n)\) 求 \(f(n)\),那么:
1.2 二项式反演 2
\(g(n)\) 表示从 \(N\) 个不同元素 钦定/选至少 \(n\) 个元素形成特定结构的方案数;
\(f(n)\) 表示 恰好 使用 \(n\) 个不同元素(且这 \(n\) 个元素包含所有被钦定的)形成特定结构的总方案数。
若已知 \(f(n)\) 求 \(g(n)\),那么显然有:
若已知 \(g(n)\) 求 \(f(n)\),那么:
上述已知 \(g(n)\) 求 \(f(n)\) 的过程,就称为 「二项式反演」。
证明可以将前一个式子的 \(g(n)\) 代到后一个式子中,并使用组合恒等式做一些「转化与化归」即可。
2 例题
一个 Trick 是:
如果 \(g\) 是一个求和式,那么交换求和顺序,可以对 \(\sum_{i=n}^{N}{i\choose n}(-1)^{i-n}\) 补一个 \(0\) 次项之后用二项式定理【 「BZOJ2863」愤怒的元首】
2.1 二项式反演 2
下面的一部分比较远古了,\(g,f\) 的一些定义可能不太对。
「BZOJ 2839」集合计数
\(g(n)\) 表示最终交集中元素包含了 钦定 的 \(n\) 个元素的方案数;
\(f(n)\) 表示最终交集中 至少 有 \(n\) 个不同元素(且这 \(n\) 个元素包含所有被钦定的)的总方案数。
由 二项式反演 2 可知:
下考虑如何求解 \(g(i)\):
- 对于钦定的 \(i\) 个元素,其方案数为 \({n\choose i}\);
- 对于非钦定的 \(n-i\) 个元素,她们将会出现 \(2^{n-i}\) 个子集,于是子集合的选取方案数进而为 \(2^{2^{n-i}}\)。
- 注意,在计算子集个数时,算上了空集;最后再选取的子集时,亦算上了一个子集都不选的方案。而这两种方案本质上是同一种,即非钦定的元素一个都不选。故最终的 \(g(i)={i\choose i}(2^{2^{n-i}}-1)\)。
预处理后,时间复杂度为 \(O(n)\)。(然而下面的代码并没有预处理((
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5, mod = 1e9 + 7;
int n, k;
struct mint {
int val;
mint (long long x=0) { val = x%mod; }
inline mint operator + (mint x) { return (1ll*val + x.val) % mod; }
inline mint operator - (mint x) { return (1ll*val - x.val + mod) % mod; }
inline mint operator * (mint x) { return (1ll*val * x.val) % mod; }
inline mint operator += (mint x) { return *this = *this + x; }
inline mint operator -= (mint x) { return *this = *this - x; }
inline mint operator *= (mint x) { return *this = *this * x; }
} ans, fac[N];
mint qpow (mint a, mint b) {
mint res = 1;
for (; b.val; b.val >>= 1, a *= a)
if (b.val & 1) res *= a;
return res;
}
mint qpow2 (long long a, long long b) {
long long res = 1;
for (; b; b >>= 1, a = (1ll*a*a)%(mod-1))
if (b & 1) res = (1ll*res*a)%(mod-1);
return res;
}
mint inv (mint x) { return qpow(x, mod-2); }
void init_fac (int _n) {
fac[0] = 1;
for (int i = 1; i <= _n; i++) fac[i] = fac[i-1] * i;
}
mint C (int n, int m) { return fac[n] * inv(fac[m]*fac[n-m]); }
mint g (int i) {
return C(n,i) * (qpow(2, qpow2(2, n-i)) - 1);
}
int main () {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
init_fac(n);
for (int i = k; i <= n; i++) {
// printf("%lld %lld %lld %lld\n", C(i,k), C(n,i), ((i-k)&1?-1:1), g(i));
if ((i & 1) == (k & 1))
ans += C(i,k) * g(i);
else
ans -= C(i,k) * g(i);
}
cout << ans.val;
return 0;
}
「BZOJ3622」已经没有什么好害怕的了
\(g(n)\) 表示最终配对方案中包含了 恰有 的 \(n\) 对元素,对每个元素满足 \(a_i > b_i(1\le i\le n)\) 的方案数;
\(f(n)\) 表示最终交集中 至少 有 \(n\) 个不同元素,满足 \(a_i > b_i(1\le i\le n)\)(且这 \(n\) 个元素包含所有被钦定的)的总方案数。
由于总的对数是确定的 \(n\),所以答案即为 \(f(\frac{n+k}2)\)。
由 二项式反演 2 可知:
下考虑如何求解 \(g(i)\):
首先对 \(a,b\) 排序。
考虑 DP,令 \(dp[i][j]\) 表示对于 \(a\) 的前 \(i\) 项,配对了 \(j\) 对 \(a_i>b_i\)。
\(\lambda(x)\) 表示对于 \(x\) 有多少个 \(b_i\) 是小于 \(x\) 的。有如下状态转移方程:
于是 \(g(i)=dp[n][i]\times (n-i)!\)。至少有 \(i\) 对满足,剩下的 \((n-i)\) 个元素随便排即可。
时间复杂度为 DP 的 \(O(n^2)\)。
「CF1228E」 Another Filling the Grid
\(g(n)\) 表示最终方案中包含了 恰有 的 \(n\) 对元素,对每个元素满足 \(a_i > b_i(1\le i\le n)\) 的方案数;
\(f(n)\) 表示最终交集中 至少 有 \(n\) 个不同元素,满足 \(a_i > b_i(1\le i\le n)\)(且这 \(n\) 个元素包含所有被钦定的)的总方案数。
咕。
「CF997C」Sky Full of Stars
\(f(i,j)\) 表示最终方案中 恰有 \(i\) 行相同的,\(j\) 列相同的;
\(g(i,j)\) 表示最终方案中 至少 \(i\) 行相同的,\(j\) 列相同的。
答案即为:\(Ans=3^{n\times n}-f(0,0)\)
由 高维二项式反演 2 可知:
特别的 \(n=m=0\) 时,有:
下考虑如何求 \(g(i,j)\),再求 \(f(0,0)\)。
分类讨论:
-
\(i\ne0\ \text{and}\ j\ne0\)
此时,一定有行列相交,所以这 \(i\) 行和 \(j\) 列中的颜色都是一样的。
\(\begin{aligned}g(i,j)=3^{(n-i)(n-j)}{n\choose i}{n\choose j}\end{aligned}\times3\)
\[\begin{aligned}f(0,0)&=\sum_{i=1}^{n}\sum_{j=1}^{n}(-1)^{i+j}3^{(n-i)(n-j)+1}{n\choose i}{n\choose j}\\&=\color{lightgrey}\sum_{d=2}^{2n}(-1)^d3^{n^2-nd+1}{n\choose i}\sum_{i=1}^{d-1}3^{id-i^2}{n\choose d-i}&\color{lightgrey}\text{【不太行,组合数前的系数难搞】}\\&=\sum_{i=1}^{n}(-1)^i3^{n^2-ni+1}{n\choose i}\sum_{j=1}^{n}{n\choose j}(-1)^{j}3^{j(n+i)}\\&=\sum_{i=1}^{n}(-1)^i3^{n^2-ni+1}{n\choose i}\sum_{j=1}^{n}{n\choose j}1^{n-j}{\left(-3^{(i-n)}\right)^j}\\&=\sum_{i=1}^{n}(-1)^i3^{n^2-ni+1}{n\choose i}\left(\left(1-3^{(i-n)}\right)^n-1\right)&\text{【二项式定理】}\\\end{aligned} \]然后就可以 \(O(n\log n)\) 做了。
-
\(i=0\ \text{and}\ j\ne 0\)
此时,另外的 \(j\) 列每两列之间不一定颜色相同。
\(\begin{aligned}g(0,j)=3^{n(n-j)}{n\choose j}\times 3^j\end{aligned}\)
直接算即可。
-
\(i\ne0\ \text{and}\ j= 0\)
与 \(i=0\) 同理。
\(\begin{aligned}g(i,0)=3^{n(n-i)}{n\choose i}\times 3^i\end{aligned}\)
直接算即可。
-
\(i=0\ \text{and}\ j=0\)
完全乱放。
\(g(0,0)=3^{n\times n}\)
综上所述: