【BZOJ2839集合计数】容斥,组合
这道题首先从N个数中选出K个数出来把他们成为交集的那些数,可以得到方案C(n,k) 问题转化为在(N-K)个数中公共交集为空集的方案数 首先对于x个数来说,有2^x种子集,每个子集考虑选还是不选就有2^(2^x)种方案 给定一个集合交集大小至少为i的情况,即最后一个集合交集>=i的情况 选i的时候要乘上C(n-k,i) 容斥就变成 2 ^( 2^(0>=) ) -2 ^ ( 2^(1>=) ) + 2^ ( 2^ (2>=) )……….. (这里的0>=,1>=为至少包含元素的方案数)
于是乎,答案就出来了 (有可能有错,欢迎挑错)
于是乎,答案就出来了 (有可能有错,欢迎挑错) #include<cstdio> #include<iostream> #include<cmath> using namespace std; typedef long long ll; const ll mod = 1000000007; ll n,k,inv[1000005],jc[1000005]; //ll f2[1000005]; ll ksm(ll a,ll b) { ll ans=1; a%=mod; while(b) { if(b&1) ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } void init() { ll i;jc[1]=1,jc[0]=1; for(i=2;i<=n;++i) jc[i]=jc[i-1]*i%mod; inv[n]=ksm(jc[n],mod-2); for(i=n-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod; // f2[0]=1; f2[1]=2; // for(i=2;i<=n;i++) f2[i]=(f2[i-1]<<1LL)%mod; //这么写相当于对指数取模,瞬间爆炸!!! } inline ll getc(ll a,ll b)//C(a,b) { return jc[a]*inv[b]%mod*inv[a-b]%mod; } int main() { scanf("%lld%lld",&n,&k); init(); ll aha=n-k; ll f=(aha&1)?-1:1,tmp=0,tt,kao=2; for(ll i=aha;i>=0;i--,kao=kao*kao%mod) { tt=getc(aha,i)*kao%mod; tmp=(tmp+tt*f)%mod; f=-f; } tmp=tmp*getc(n,k)%mod; printf("%lld",(tmp%mod+mod)%mod); }