二项式反演
本文原在 2024-05-23 13:52 发布于本人洛谷博客。
一、简单介绍
1. 钦定与恰好
如在
2. 公式
设
设
二、应用
1. 字符串匹配
给定
个长度相同的字符串 ,如果一个字符串 每一位都和 相同(其中 ?代表和任何字母都相同),那么就称这两个字符串匹配。求
恰好能匹配 个字符串的方案数。
。
设
考虑求
用二进制枚举枚举不同字符串的组合,然后判断这 ? 的位,那么贡献值就要乘上 a~z)的任何数。
然后二项式反演即可,
for (int mask = 0; mask < 1 << n; mask++) {
int cnt = 0;
bool b = false;
string t = "";
for (int i = 0; i < l; i++) t += '?';
for (int i = 0; i < n; i++) {
if ((1 << i) & mask) {
cnt++;
for (int j = 0; j < l; j++) {
if (s[i][j] == '?' or t[j] == s[i][j]) continue;
else if (t[j] == '?') t[j] = s[i][j];
else {
b = true;
break;
}
}
}
if (b) break;
}
if (b) continue;
int res = 0;
for (int j = 0; j < l; j++)
if (t[j] == '?') res++;
f[cnt] = (f[cnt] + mypow(26, res)) % mod;
}
for (int i = k; i <= n; i++) ans = (ans + mypow(-1, i - k) * C(i, k) % mod * f[i] % mod + mod) % mod;2. P4859 已经没有什么好害怕的了
给出两个数组
, ,其中 个数互不相同,将 和 中的数两两配对,设 的有 个, 的有 个,求 的方案数。
。
易得
同样,设
考虑求
设
其中
由于是钦定,剩下的数能随便配对,有
故
二项式反演即可。
if ((n + k) % 2) {
cout << 0;
return 0;
}
k = (n + k) / 2;
sort(a + 1, a + n + 1);
sort(b + 1, b + n + 1);
for (int p = 1, q = 0; p <= n; p++) {
while (q < n and b[q + 1] < a[p]) q++;
r[p] = q;
}
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
dp[i][0] = 1;
for (int j = 1; j <= i; j++)
dp[i][j] = (dp[i - 1][j] + (r[i] - j + 1) * dp[i - 1][j - 1] % mod) % mod;
}
for (int i = 0; i <= n; i++)
f[i] = dp[n][i] * fac[n - i] % mod;
for (int i = k; i <= n; i++)
ans = (ans + (mypow(-1, i - k) + mod) % mod * C(i, k) % mod * f[i] % mod) % mod;3. P10596 BZOJ2839 集合计数
设
二项式反演,设
如何计算
倒着算即可。
4. P10597 BZOJ4665 小 w 的喜糖
设
除去的原因是,没被钦定的人不能随便重排。