zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    417 Pacific Atlantic Water Flow 太平洋大西洋水流
    416 Partition Equal Subset Sum 分割相同子集和
    415 Add Strings 字符串相加
    414 Third Maximum Number 第三大的数
    413 Arithmetic Slices 等差数列划分
    412 Fizz Buzz
    410 Split Array Largest Sum 分割数组的最大值
    409 Longest Palindrome 最长回文串
    day22 collection 模块 (顺便对比queue也学习了一下队列)
    day21 计算器作业
  • 原文地址:https://www.cnblogs.com/wxjor/p/9557029.html
Copyright © 2011-2022 走看看