【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);
} 

     
posted @ 2018-03-20 23:37  Newuser233  阅读(5)  评论(0)    收藏  举报