首先我们知考虑只有一种交集
交集的大小为K,那么有2N-K个子集包含了这K个元素(确定K个元素,再从剩下N-K个元素任意选取,有2N-K种组合)
用这2N-K个子集能有2^(2^(N-K))种组合,再减去1个空集
一共有CKN种交集,这样得出tmp(K)=CKN *(2^(2^(N-K)-1)种方法
这里面包含了交集大小大于K的取法,所以还要进行容斥
对于交集大小为L,有tmp(L)=CLN *(2^(2^(N-L)-1)种取法
但是tmp(K)多的不止一倍的tmp(L),因为对于每一种交集都多加了tmp(L)
多出CKL 倍
例如:
集合为{A,B,C,D,E},K=2
tmp(K)包含了交集大小为K,K+1,K+2...N的取法种数
合法的交集是AB,AC,AD...
但是出现了像BCDE这样不合法的交集
只计算交集为BC时多余BCDE交集,算BD,BE...同样多出
所以BCDE被多算了C24次
容斥的话,L-N是奇数就减去CKL *tmp(L),L-N是偶数就加上CKL *tmp(L)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 const long long p=(int)1e9+7; 6 const int MAXN=(int)1e6+100; 7 int N,K; 8 long long fac[MAXN],faci[MAXN]; 9 long long qp[MAXN]; //2^2^i 10 long long ans=0; 11 long long qpow(long long a,long long b,long long p){ 12 if(a==0) 13 return 0; 14 a%=p; 15 long long out=1; 16 while(b){ 17 if(b&1) 18 out=(out*a)%p; 19 b>>=1; 20 a=(a*a)%p; 21 } 22 return out; 23 } 24 25 long long C(int n,int m){ 26 if(m>n) 27 return 0; 28 return ((fac[n]*faci[m]%p)*faci[n-m])%p; 29 } 30 31 long long T(int i){ //2^(2^(N-i)) 32 return qp[N-i]-1; 33 } 34 35 int main(){ 36 scanf("%d%d",&N,&K); 37 qp[0]=2; 38 qp[1]=4; 39 for(int i=2;i<=N;++i) 40 qp[i]=qp[i-1]*qp[i-1]%p; 41 fac[0]=faci[0]=1; 42 for(int i=1;i<=N;++i) 43 fac[i]=(fac[i-1]*i)%p; 44 faci[N]=qpow(fac[N],p-2,p); 45 for(int i=N-1;i>=1;--i) 46 faci[i]=(faci[i+1]*(i+1))%p; 47 ans=C(N,K)*T(K)%p; 48 for(int i=K+1;i<=N;++i){ 49 long long fg=( (i-K) & 1 ) ? -1:1; 50 ans+=(fg*C(i,K)*C(N,i)%p)*T(i)%p; 51 ans=(ans+p)%p; 52 } 53 printf("%lld ",ans); 54 }