zoukankan      html  css  js  c++  java
  • BZOJ2839:集合计数(容斥,组合数学)

    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;

    Solution

    首先考虑一下容斥
    设$f(k)$表示选出一些集合使它们交集大小至少为$k$的方案数。
    那么$f(k)=C_n^k imes (2^{2^{n-k}}-1)$
    这玩意儿怎么理解呢?也就是先把那$i$个数确定下来,然后有$2^{n-k}$个集合可以包含那$k$个数。这些集合要么选要么不选,但不能一个都不选,也就是不能为空集。所以有$2^{2^{n-k}}-1$种选择方法。
    那么容斥系数呢?可以发现当计算交集至少为$k$的方案时候,交集至少为$j$的方案($j>k$)会被计算$C_j^k$次。
    也就是说,
    $f(k)$的系数为$1$。
    $f(k+1)$的系数为$-C_{k+1}^k$。
    $f(k+2)$的系数为$-C_{k+2}^k+C_{k+1}^k imes C_{k+2}^{k+1}=C_{k+2}^k$
    为什么$f(k+2)$能那么推呢……因为$C_N^M imes C_M^S=C_N^S imes C_{N-S}^{N-M}$
    搞到现在基本可以组合计数搞搞出解了,至于那个大的一比的$2^{2^{n-k}}$,根据欧拉定理直接指数取模$φ(MOD)$就好了,显然$φ(MOD)=MOD-1$。

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #define N (1000009)
     4 #define LL long long
     5 #define MOD (1000000007)
     6 using namespace std;
     7 
     8 LL n,k,ans,inv[N],fac[N],facinv[N],p[N];
     9 
    10 void Init()
    11 {
    12     inv[1]=fac[0]=facinv[0]=p[0]=1;
    13     for (int i=1; i<=n; ++i)
    14     {
    15         if (i!=1) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
    16         fac[i]=fac[i-1]*i%MOD; facinv[i]=facinv[i-1]*inv[i]%MOD;
    17         p[i]=p[i-1]*2%(MOD-1);
    18     }
    19 }
    20 
    21 LL Qpow(LL a,LL b)
    22 {
    23     LL ans=1;
    24     while (b)
    25     {
    26         if (b&1) ans=ans*a%MOD;
    27         a=a*a%MOD; b>>=1;
    28     }
    29     return ans;
    30 }
    31 
    32 LL C(LL n,LL m)
    33 {
    34     if (n<m) return 0;
    35     return fac[n]*facinv[m]%MOD*facinv[n-m]%MOD;
    36 }
    37 
    38 int main()
    39 {
    40     scanf("%lld%lld",&n,&k);
    41     Init();
    42     for (int i=k,j=1; i<=n; ++i,j=-j)
    43         ans+=j*C(n,i)*(Qpow(2,p[n-i])-1)%MOD*C(i,k)%MOD;
    44     ans=(ans%MOD+MOD)%MOD;
    45     printf("%lld
    ",ans);
    46 }
  • 相关阅读:
    序列JSON数据和四种AJAX操作方式
    jquery.validate和jquery.form.js实现表单提交
    JQuery Validate使用总结1:
    HOWTO: Include Base64 Encoded Binary Image Data (data URI scheme) in Inline Cascading Style Sheets (CSS)(转)
    SharePoint 2007 使用4.0 .Net
    动态IP解决方案
    取MS CRM表单的URL
    从Iframe或新开的窗口访问MS CRM 2011(转)
    Toggle or Hidden MS CRM Tab
    Windows 2008下修改域用户密码
  • 原文地址:https://www.cnblogs.com/refun/p/10145811.html
Copyright © 2011-2022 走看看