• [BZOJ2839] 集合计数


    [BZOJ2839] 集合计数

    Description

    一个有N个元素的集合有2N个不同子集(包含空集),现在要在这2N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为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;

    试题分析

    依旧不能保证取出来一定是严格K个,所以设(f_k)为交集大小至少为k的方案数。
    那么(f_k=inom{n}{k} (2^{2^{n-k}} -1))
    上面的(2^{n-k})代表集合数量,也就是要去掉k个剩下的集合数量,这些集合一定包含交集。
    然后还要将这些集合挑选若干个选出来,最后-1是一个集合都没有选的。
    那么设容斥系数为(g_k),有(ans=sum_{i=0}^K g_i imes f_i)
    于是有:$$[xm]=sum_{i=0}^K f_i imes inom{n}{i}$$
    根据二项式反演:$$f(n) = sum_{i = 0}^{n}inom{n}{i}g(i) Leftrightarrow g(n) = sum_{i = 0}^{n} (-1)^{n - i} inom{n}{i} f(i)$$
    有:$$f(x)=sum_{i=0}^x (-1)^{x-i} inom {x}{i} [i
    m]$$
    带回到原式中即可。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
     
    using namespace std;
    #define LL long long
     
    inline LL read(){
        LL x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const LL INF = 2147483600;
    const LL MAXN = 2000010;
    const LL Mod = 1000000007;
     
    LL N,M; LL inv[MAXN+1],fac[MAXN+1],ifac[MAXN+1],Pow[MAXN+1];
    inline LL Powl(LL A,LL B){
        LL res=1LL; for(; B ; B>>=1,A=A*A%Mod) if(B&1) res=res*A%Mod; return res;
    }
    inline void init(){
        inv[1]=1; fac[1]=1; ifac[1]=1; 
        for(LL i=2;i<=N;i++) fac[i]=fac[i-1]*i%Mod;
        for(LL i=2;i<=N;i++) inv[i]=(Mod-(Mod/i)*inv[Mod%i])%Mod;
        for(LL i=2;i<=N;i++) ifac[i]=ifac[i-1]*inv[i]%Mod;
        Pow[0]=1; for(LL i=1;i<=N;i++) Pow[i]=Pow[i-1]*2LL%(Mod-1);
        return ;
    }
    inline LL C(LL n,LL m){
        if(n==m) return 1; if(!m) return 1;
        //printf("ifac[%lld] = %lld   ifac[%lld] = %lld   fac[%lld] = %lld
    ",n-m,ifac[n-m],m,ifac[m],n,fac[n]);
        return fac[n]*ifac[m]%Mod*ifac[n-m]%Mod;
    }
    LL ans=0;
     
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        N=read(),M=read(); init();
        for(LL i=M;i<=N;i++){
            LL ret=((i-M)&1)?-1:1;
            //cout<<C(i,M)<<" "<<C(N,i)<<" "<<Pow[N-i]<<endl;
            ret=ret*C(i,M)%Mod*C(N,i)%Mod*(Powl(2LL,Pow[N-i])-1)%Mod;
            ret=(ret%Mod+Mod)%Mod; (ans+=ret)%=Mod;
        } printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    phpcms新建模板页教程
    Linux方向职业规划
    Codeforces Round #417 (Div. 2)-A. Sagheer and Crossroad
    Codeforces Round #396(Div. 2) A. Mahmoud and Longest Uncommon Subsequence
    ACM hdu 3336 Count the string
    ACM KMP 格式输入导致TLE
    swing JTable 更新数据
    swing JTable
    HashMap 和 HashTable 区别
    Java中next()和nextLine()
  • 原文地址:https://www.cnblogs.com/wxjor/p/9557029.html
Copyright © 2020-2023  润新知