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

    题意

    (n) 个元素可以构成 (2^n) 种集合(包括空集),求在其中选出大于等于一个集合,使得这些集合的交的大小为 (k)

    (0le kle nle 10^6)

    分析

    选出 (k) 个作为交集,那么问题转化成在 (n-k) 个元素组成的集合中选出大于等于一个集合,使得它们的交集为空。

    对这个东西进行容斥,用交集至少为0-交集至少为1+交集至少为2……,即若要求 (n) 个元素组成交集为空的方案数:

    [sum _{i=0}^n(-1)^iinom n i (2^{2^{n-i}}-1) ]

    即容斥,决定交集是什么,剩下的 (n-i) 个元素又组成 (2^{n-i}) 种集合,可以任取,但是不能取空集。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long giant;
    const int maxn=1e6+1;
    const int q=1e9+7;
    inline int Plus(int x,int y) {return ((giant)x+(giant)y)%q;}
    inline int Sub(int x,int y) {return Plus(x,q-y);}
    inline int Multi(int x,int y) {return (giant)x*y%q;}
    int inv[maxn],fac[maxn],ifac[maxn],n,k;
    inline int C(int n,int m) {return Multi(Multi(fac[n],ifac[m]),ifac[n-m]);}
    inline int mi(int x,int y,int t=0) {
    	if (!t) t=q;
    	int ret=1;
    	for (;y;y>>=1,x=(giant)x*x%t) if (y&1) ret=(giant)ret*x%t;
    	return ret;
    }
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    #endif
    	cin>>n>>k;
    	inv[1]=fac[1]=ifac[1]=fac[0]=ifac[0]=1;
    	for (int i=2;i<=n;++i) {
    		inv[i]=Multi(q-q/i,inv[q%i]);
    		fac[i]=Multi(fac[i-1],i);
    		ifac[i]=Multi(ifac[i-1],inv[i]);
    	}
    	int ans=C(n,k),aux=0;
    	n-=k;
    	for (int i=0;i<=n;++i) {
    		int tmp=Multi(C(n,i),Sub(mi(2,mi(2,n-i,q-1)),1));
    		aux=Plus(aux,i&1?q-tmp:tmp);
    	}
    	ans=Multi(ans,aux);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    手脱ASPack v2.12变形壳2
    手脱nSPack 2.1
    WCF分布式开发步步为赢(1):WCF分布式框架基础概念
    一个经典例子让你彻彻底底理解java回调机制
    C#三层架构详细解剖
    eclipse快捷键及各种设置
    设计模式总结
    程序猿也爱学英语(上)
    关于PDA、GPS等动态资源的几种GIS解决方案
    通过VS2010性能分析来查找代码中那些地方最损耗资源
  • 原文地址:https://www.cnblogs.com/owenyu/p/7376170.html
Copyright © 2011-2022 走看看