Description
一個有N個元素的集合有2N個不同子集(包含空集),現在要在這2N個集合中取出若干集合(至少一個),使得
它們的交集的元素個數爲K,求取法的方案數,答案模1000000007。(是質數喔~)
Solution
這個容斥就很簡單了
考慮設g[k]表示至少k個相同的答案,f[k]表示恰好k個相同的答案
顯然有
考慮g[]的含義,不難得到
然後有一個神奇的變換就是
這是一個反演,證明的話帶入一下就可以了。。
於是我們就可以求恰好k的答案了
沒有交,本地拍了一下似乎沒毛病
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int MOD=1000000007;
const int N=200005;
LL fac[N],inv[N],f[N],g[N];
LL C(int n,int m) {
return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
LL ksm(LL x,LL dep,int MOD) {
LL res=1;
for (;dep;dep>>=1) {
(dep&1)?(res=res*x%MOD):0;
x=x*x%MOD;
}
return res;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
fac[0]=fac[1]=1; rep(i,2,N-1) fac[i]=fac[i-1]*i%MOD;
inv[0]=inv[1]=1; rep(i,2,N-1) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
rep(i,2,N-1) inv[i]=inv[i-1]*inv[i]%MOD;
int n,k; scanf("%d%d",&n,&k);
rep(i,1,n) g[i]=C(n,i)*(ksm(2,ksm(2,n-i,MOD-1),MOD)-1)%MOD;
rep(j,k,n) {
LL tmp=C(j,k)*g[j]%MOD;
if ((j-k)&1) f[k]=(f[k]+MOD-tmp)%MOD;
else f[k]=(f[k]+tmp)%MOD;
}
printf("%lld", f[k]);
return 0;
}