集合计数(容斥原理)

题目大意

     一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007.

题解

  首先很容易想到从n个元素中选出k个作为交集的方案数 C(n,k)

  以下是错误思路,想偏了……(-_-)!

    然后对于每个k在剩余的n-k个元素中任选元素,与k共同组成一个集合,共有2^(n-k)种集合,这些个集合,又有2^(2^(n-k))中方案使得交集为k

  然后……就会发现有对于不同的k的方案有一堆重复(容斥啊!)……不知道咋容斥

  正解

  从剩下的n-k个元素中选元素,组成没有交集的那么多个集合,使得他们的交集只能是k

  发现上面错解里面有一些方案中的交集是k+1个元素,那么减去这些个C(n-k,1)*2^(2^(n-k-1)),这样又会多减去好几次交集为k+2的方案,再加上,

怎样容斥就出来了

  即对于每个k而言,加上k个交集的方案,减去k+1个交集的方案,加上k+2个交集的方案,……加上(-1)^(n-k)*(n个交集的方案)

  干成一块,枚举交集i,同时不能为空集(即不能一个都不选),2^(2^(n-i))要减去全都不选的情况: ans+=(-1)^(i-k)*C(n,i)*(2^(2^(n-i))-1)*C(i,k);

  一开始我的代码濒临TLE

  

  然后学了一手线性求逆元,代码如下:   

jc[0]=1;
for(int i=1;i<=n;i++) jc[i]=(long long)(jc[i-1]*i)%mod;
inv[n]=pow(jc[n],mod-2);
for(int i=n-1;i>=0;i--) inv[i]=((inv[i+1]%mod)*(i+1)%mod)%mod;
线性求逆元

 

         

  经过我的不断修改,我终于发现了30到AC的秘密

    ans+=(C(i,n)*((1ll*(pow(2,q[n-i])-1)*C(k,i)*1ll)%mod*ha*1ll))%mod; 我没写那个括号(玄学问题,我也不知道,有大佬知道的话,麻烦告诉一声,lockey在此%)

 

  AC代码

 

#include<iostream>
#include<cstdio>
using namespace std;
const long long mod=1000000007;
int n,k;
long long q[1100000],jc[1100000],inv[1100000];
long long ans=0;
long long pow(long long a,long long b){
    long long ans=1;
    a%=mod;
    while(b){
        if(b&1) ans=(long long)(ans*a)%mod;
        b>>=1;
        a=(long long)(a*a)%mod;
    }
    return ans%mod;
}
long long C(long long m,long long n){
    if(!m||m==n) return 1;
    if(m>n) return 0;
    if(m<mod&&n<=mod)
        return ((long long)((long long)(jc[n]*inv[m])%mod)*inv[n-m])%mod;
    return ((long long)C(m%mod,n%mod)*C(m/mod,n/mod))%mod;
}
int main(){
    scanf("%d%d",&n,&k);
    jc[0]=1,q[0]=1;
    for(int i=1;i<=n;i++) jc[i]=(long long)(jc[i-1]*i)%mod;
    inv[n]=pow(jc[n],mod-2);
    for(int i=n-1;i>=0;i--) inv[i]=((inv[i+1]%mod)*(i+1)%mod)%mod;
    for(int i=1;i<=n;i++) q[i]=(q[i-1]*2)%(mod-1);
    long long ha=1;
    for(int i=k;i<=n;i++,ha=-ha){
        ans+=(C(i,n)*((1ll*(pow(2,q[n-i])-1)*C(k,i)*1ll)%mod*ha*1ll))%mod;
    }
    cout<<1ll*(1ll*(ans+mod)%mod+mod)%mod<<endl;
}
View Code

 

posted @ 2019-07-03 15:38  Lockey_T  阅读(538)  评论(0编辑  收藏  举报