zoukankan      html  css  js  c++  java
  • bzoj2839 集合计数

    题意

    n个元素组成的集合有(2^n)个,现在在这些集合中选出若干个(至少1个)使得它们交集的大小为k,问选法种数.
    n<=10^6

    分析

    做得有点麻烦...有点怀疑人生...
    如果两种选法中交集中包含的k个元素不同,那么一定是不同的选法.所以可以先确定交集包含哪些元素,于是答案里有一个(C^{k}_{n}).接下来我们选的每个集合都必须包含这k个元素.包含这k个元素的集合有(2^{n-k})个,那么从中选出若干个但不能一个都不选的方案数是(2^{2^{n-k}}-1).
    那么最终答案肯定不是(C^{k}_{n}(2^{2^{n-k}}-1)),因为这里面算的方案只是交集至少有k个元素,其中的方案的实际交集大小可以大于k.
    (C^{k}_{n}(2^{2^{n-k}}-1))算的也不是交集至少k个元素的方案数,因为一个交集元素个数大于k的选取方案在这个式子里不止贡献1.假如一个方案A中交集大小为(j(j>k)),那么我们枚举(C^{k}_{n})种选出k个元素作为交集的方式时,如果k个元素都是方案A中j个交集元素中的,那么方案A就会在这里被统计一次,因此方案A对这个式子的贡献为(C^{k}_{j}).
    (g[k]=C^{k}_{n}(2^{2^{n-k}}-1),f[k])为交集大小恰好等于k的选取方案数.
    那么(g[k]=sum^{n}_{i=k}C^{k}_{i}f[i])
    (f[k])移项就可以DP了.由此可以得到一个(O(n^2))的暴力DP,从(f[n])(f[k])依次求解.

    现在直接考虑每个(g[i])(f[k])贡献的系数.假设这个系数是(h[k][i](kle i),)那么(f[k]=sum_{i=k}^{n}g[i] imes h[k][i])
    这个系数也可以暴力DP来计算.显然(h[i][i]=1),对于其他情况,(g[i])先对(f[j])作出贡献再从(f[j])贡献到(f[i]),于是(h[k][i]=sum_{j=k+1}^{i} C_{j}^{k}h[j][i])
    然后,然后我就不会了,然后,然后我就去看网上的题解,发现题解的式子长得和我推出来的形式差不多,只不过把(h[k][i])换成了((-1)^{i-k}C_{i}^{k}).抱着怀疑的心情我写了个暴力DP算这个系数,发现确实是这样...一定要记得数学上来先打表
    然后...(h[k][i]=(-1)^{i-k}C_{i}^{k})这个结论是有理有据的,我们可以归纳.
    (k=i)显然成立
    否则(h[k][i]=sum_{j=k+1}^{i} (-1) imes C_{j}^{k}h[j][i]=sum_{j=k+1}^{i} C_{j}^{k} imes (-1)^{i-j+1} imes C_{i}^{j})
    考虑(C_{i}^{j} imes C_{j}^{k})的含义,相当于从i个物品里选出j个,再从j个里选出k个.相当于把i个物品分为三组,分别有((i-j),(j-k),k)个.那么也相当于(C_{i}^{k} imes C_{i-k}^{i-j}),于是(h[k][i]=(-1) imes sum_{j=k+1}^{i} (-1)^{i-j} imes C^{i-j}_{i-k} imes C^{k}_{i})
    (=(-1) imes sum_{j=k}^{i} (-1)^{i-j} imes C^{i-j}_{i-k} imes C^{k}_{i}+(-1)^{i-k} imes C^{k}_{i})
    (sum_{j=k}^{i} (-1)^{i-j} imes C^{i-j}_{i-k})用一下二项式定理,就是((1-1)^{i-k}),所以相当于(h[k][i]=(-1)^{i-k} imes C^{k}_{i})
    这个式子似乎是可以直接容斥搞出来,然而辣鸡liu_runda并不会

    #include<cstdio>
    const int mod=1000000007,maxn=1000005;
    int fac[maxn],inv[maxn];
    int qpow(int a,int x,int M){
      int ans=1;
      for(;x;x>>=1,a=a*1ll*a%M){
        if(x&1)ans=ans*1ll*a%M;
      }
      return ans;
    }
    void init(){
      fac[0]=1;
      for(int i=1;i<maxn;++i)fac[i]=fac[i-1]*1ll*i%mod;
      inv[maxn-1]=qpow(fac[maxn-1],mod-2,mod);
      for(int i=maxn-1;i>=1;--i)inv[i-1]=inv[i]*1ll*i%mod;
    }
    int C(int n,int m){
      return fac[n]*1ll*inv[m]%mod*inv[n-m]%mod;
    }
    int main(){
      init();
      int ans=0;
      int n,k;scanf("%d%d",&n,&k);
      int flag=1;
      for(int i=k;i<=n;++i){
        if(flag){
          ans=(ans+C(n,i)*1ll*C(i,k)%mod*(qpow(2,qpow(2,n-i,mod-1),mod)-1+mod)%mod)%mod;
        }else{
          ans=(ans-C(n,i)*1ll*C(i,k)%mod*(qpow(2,qpow(2,n-i,mod-1),mod)-1+mod)%mod+mod)%mod;
        }
        flag^=1;
      }
      printf("%d
    ",ans);
      return 0;
    }
    
    
  • 相关阅读:
    判断上传的文件是否为图片
    P17 更多文件操作
    p16 读写文件
    VMWare Workstation 7.1.2.301548
    Oracle SQL Developer语言设置
    HTC Android 存储卡文件夹
    CentOS 添加EPEL
    Silverlight应用程序的本地通讯
    SQL Server 2008 R2 序列号
    VMware 7 注册码
  • 原文地址:https://www.cnblogs.com/liu-runda/p/7119330.html
Copyright © 2011-2022 走看看