bzoj 2839: 集合计数 排列组合+容斥原理

来源:互联网 发布:医疗器械销售公司知乎 编辑:程序博客网 时间:2024/05/14 17:05

题意

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

分析

首先我们枚举交集元素,方案显然为Ckn。那么我们选择的集合则必然要包含这k个元素,显然满足条件的集合有2nk个,因为集合的数量不固定但不能为0,则选择的方案有22nk1种。但我们发现会有一些选择方案使得交集包含另外的元素,于是就可以大力容斥一波。具体来说就是枚举另外包含的元素数量s,若s为偶数则答案加上22nks1,否则就减去即可。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=1000005;const int MOD=1000000007;int n,k,jc[N],ny[N];int ksm(int x,int y,int mo){    int ans=1;    while (y)    {        if (y&1) ans=(LL)ans*x%mo;        x=(LL)x*x%mo;y>>=1;    }    return ans;}int C(int n,int m){    return (LL)jc[n]*ny[m]%MOD*ny[n-m]%MOD;}int get(int s){    int x=ksm(2,s,MOD-1);    return ksm(2,x,MOD)-1;}int main(){    scanf("%d%d",&n,&k);    jc[0]=ny[0]=1;    for (int i=1;i<=n;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=ksm(jc[i],MOD-2,MOD);    LL ans=0;    for (int i=0;i<=n-k;i++)        if (i%2==0) (ans+=(LL)C(n-k,i)*get(n-k-i))%=MOD;        else (ans-=(LL)C(n-k,i)*get(n-k-i))%=MOD;    ans=(LL)ans*C(n,k)%MOD;    if (ans<0) ans+=MOD;    printf("%lld",ans);    return 0;}
原创粉丝点击