前言
- 感谢学姐 Estelle_N(应该没打错)
- msjing之前自学过二反但是直接从入门到出门了,听完学姐讲课后就会了/bx
前置芝士
二项式反演
- 令 \(f_n\) 为恰好使用 \(n\) 个不同元素形成特定结构的方案数,\(g_n\) 为从 \(n\) 个不同元素中选出 \(i \ge 0\) 个元素形成特定结构的总方案数(即至少)
- 那么我们有
$g_n = \sum\limits_{i=0}^{n}{\binom{n}{i} \times f_i}$
$f_n = \sum\limits_{i=0}^{n}{\binom{n}{i} \times (-1)^{n-i} \times g_i}$
- 上述从 \(f_n\) 求 \(g_n\) 和从 \(g_n\) 求 \(f_n\) 的过程成为二项式反演
证明
- 我们证明 \(f_n = \sum\limits_{i=0}^{n}{\binom{n}{i} \times (-1)^{n-i} \times g_i}\)
- 我们先把 \(g_n = \sum\limits_{i=0}^{n}{\binom{n}{i} \times f_i}\) 带入,有
$f_n = \sum\limits_{i=0}^{n}{\binom{n}{i}} \times (-1)^{n-i} \times \sum\limits_{j=0}^{i}{\binom{i}{j} \times f_j}$
- 把 \(\sum\limits_{j=0}^{i}\) 提前,有
$\sum\limits_{i=0}^{n} \sum\limits_{j=0}^{i} \binom{n}{i} \binom{i}{j} \times (-1)^{n-i} \times f_j$
$\binom{n}{i} \binom{i}{j} = \binom{n}{j} \binom{n - j}{i - j}$
- 我们知道 \(\sum\limits_{j=0}^{i}\) 表示 \(j\) 是从 \(0\) 到 \(i\),所以我们换一下枚举,把 \(\sum\limits_{i=0}^{n} \sum\limits_{j=0}^{i}\) 改为 \(\sum\limits_{j=0}^{n} \sum\limits_{i=j}^{n}\)
- 就有
$\sum\limits_{j=0}^{n}{f_j \times \binom{n}{j}} \sum\limits_{i=j}^{n}{ \binom{n - j}{i - j} \times (-1)^{n-i} }$
$\sum\limits_{j=0}^{n}{f_j \times \binom{n}{j}} \times \sum\limits_{k=0}^{n-j}{ \binom{n-j}{k} \times (-1)^{n-j-k} }$
- 我们先搞二项式定理,这个先放着,一会说为什么
- 我们令 \(x = 1 , y = -1\),带入二项式定理,有
$(1 - 1)^n = \sum\limits_{i=0}^{n}{\binom{n}{i} \times (-1)^{n-i}}$
- 当 \(n \neq 0\) 时,原式 \(=0\),当 \(n = 0\) 时,原式 \(=1\)
- 吊不吊,\(0^0 = 1\)(貌似可能会伪?)
- 我们观察二项式定理和上面我们推的柿子,发现后面的那个 \(\sum\) 和二项式定理长得很像,我们类比一下有:\(i \to k , n \to n - j\),其中,\(\to\) 指二项式的元素对应推出的柿子中的元素,然后类比带入,有关键结论:
$C_n = \left\{
\begin{array}
&0 & n \neq j\\
1 & n = j
\end{array}
\right.$
- 我们令 \(\sum\limits_{k=0}^{n-j}{ \binom{n-j}{k} \times (-1)^{n-j-k} }\) 的值为 \(val\)
- \(n \neq j\) 时,\(val = 0\),总柿子结果为 \(0\),不管这种情况
- \(n = j\) 时,\(val = 1\),柿子化为:
$\sum\limits_{j=0}^{n}{f_j \times \binom{n}{j}}$
- 把 \(j\) 换成 \(i\),改一下元素位置,就有:
$\sum\limits_{i=0}^{n}{\binom{n}{i} \times f_i}$
- 这个柿子是等于 \(f_n\) 的,命题得证
- 证另一个同理,不证了
应用与例题
- 二项式反演的应用非常广,通常用于至少转恰好或恰好转至少,来两道例题搞一搞
- sbmqwm:你要考研啊
例题
- 题目要求至少一个,相当于求 \(g_n\),我们发现并不是很好求,所以考虑用二项式反演换成求 \(f_n\),这就很好搞了
- 我们任意取一个 \(k\),令 \(k\) 表示 \(k\) 个元素作为集合的交集,其余不要求的方案数,有:
$f_k = \binom{n}{k} \times (2^{2^{n-k}} - 1)$
$f_k = \sum\limits_{i=k}^{n}{\binom{i}{k} g_i}$
$g_k = \sum\limits_{i=k}{n}{(-1)^{i-k} \binom{n}{i} \binom{i}{k} (2^{2^{n-k}} - 1)}$
- 你把 \(\binom{n}{i} \binom{i}{k}\) 换了好像也可以,给代码
- 可能代码和讲的不太一样,毕竟是再学习
点击查看代码
#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=1e6+10,p=1000000007;
int read() {int x=0,f=1;char ch=getchar();while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}while (ch>='0' && ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,k;
struct Combinatorics
{
long long f[maxn],g[maxn];
long long ksm(long long x,long long y,long long mo)
{
long long cnt=1;
while(y)
{
if (y&1) cnt=(cnt*x)%mo;
x=(x*x)%mo;
y>>=1;
}
return cnt;
}
long long NY(long long a,long long p) {return ksm(a,p-2,p);}
void getfg(long long n)
{
f[0]=g[0]=1;
for (long long i=1;i<=n;i++) (f[i]=i*f[i-1])%=p,g[i]=NY(f[i],p);
}
long long getC(long long x,long long y) {return ((f[x]*g[x-y])%p*g[y])%p;}
long long getA(long long x,int y) {return f[x]*g[x-y]%p;}
long long d[maxn];
void getD(long long n)
{
d[1]=0,d[2]=1;
for (long long i=3;i<=n;i++) (d[i]=(i-1)*(d[i-1]+d[i-2])%p+p)%=p;
}
}c;
int main()
{
n=read(),k=read();
c.getfg(n);
long long fk=0;
for (int i=k;i<=n;i++) (fk+=c.ksm(-1,i-k,p)*c.getC(i,k)%p*c.getC(n,i)%p*(c.ksm(2,c.ksm(2,n-i,p-1),p)-1)%p)%=p;
printf("%lld\n",(fk+p)%p);
return 0;
}
后话
- msjing on 26.7.20:别用二反乱艹题,上午打 \(ACM\) 欢乐赛盯着随机化的题看了 \(1\) 个小时