IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    bzoj2839 集合计数

    summer发表于 2016-05-27 15:48:51
    love 0

    2839: 集合计数

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 243  Solved: 129
    [Submit][Status][Discuss]

    Description

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

    Input

    一行两个整数N,K

    Output

    一行为答案。

    Sample Input

    3 2

    Sample Output

    6

    HINT

    【样例说明】

    假设原集合为{A,B,C}

    则满足条件的方案为:{AB,ABC},{AC,ABC},{BC,ABC},{AB},{AC},{BC}

    【数据说明】

         对于100%的数据,1≤N≤1000000;0≤K≤N;

    容斥原理

    类似bzoj3198的思路,f[i]表示交集的个数至少是i个的方案数,最终答案ans=∑f[i]*C(i,k)*(-1)^(i-k),k≤i≤n。

    于是问题转化为如何求f[i]。

    加入限制了交集必须有i个数,等于将可选的集合范围缩小到了2^(n-i)个。而每一个集合都是可选可不选的,但是不能全部不选,所以f[i]=2^[2^(n-i)]-1。

    可以发现随着i递减,2^[2^(n-i)]每一次都是上一次的平方,然后倒着算就好了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define F(i,j,n) for(int i=j;i<=n;i++)
    #define D(i,j,n) for(int i=j;i>=n;i--)
    #define ll long long
    #define maxn 1000005
    #define mod 1000000007
    using namespace std;
    int n,k;
    ll ans,fac[maxn],inv[maxn];
    inline int read()
    {
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
    }
    inline ll getpow(ll x,ll y)
    {
    ll ret=1;
    for(;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;
    return ret;
    }
    int main()
    {
    n=read();k=read();
    fac[0]=1;
    F(i,1,n) fac[i]=fac[i-1]*i%mod;
    inv[0]=1;inv[1]=1;
    F(i,2,n) inv[i]=inv[i-mod%i]*(mod/i+1)%mod;
    F(i,2,n) inv[i]=inv[i]*inv[i-1]%mod;
    ll x=2;
    D(i,n,k)
    {
    if (i!=n) x=x*x%mod;
    ll tmp=fac[n]*inv[n-i]%mod*inv[k]%mod*inv[i-k]%mod;
    ans=(ans+tmp*(x+mod-1)%mod*((i-k)&1?mod-1:1)%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
    }



沪ICP备19023445号-2号
友情链接