• [BZOJ2839]集合计数


    [BZOJ2839]集合计数

    题目大意:

    一个有(n(nle10^6))个元素的集合有(2^n)个不同子集,现在要在这(2^n)个集合中取出若干集合(至少一个),使得
    它们的交集的元素个数为(k),求取法的方案数。

    思路:

    容斥原理。

    答案为大于等于(k)的方案数-大于等于(k+1)的方案数+大于等于(k+2)的方案数……

    其中大于等于(k)的方案数为({nchoose k}(2^{2^{n-k}}-1))

    (2^{2^{n-k}}=(2^{2^{n-k-1}})^2),因此时间复杂度可以做到(mathcal O(n))

    源代码:

    #include<cstdio>
    #include<cctype>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    typedef long long int64;
    const int N=1e6+1,mod=1e9+7;
    int fac[N],ifac[N];
    void exgcd(const int &a,const int &b,int &x,int &y) {
    	if(!b) {
    		x=1,y=0;
    		return;
    	}
    	exgcd(b,a%b,y,x);
    	y-=a/b*x;
    }
    inline int inv(const int &x) {
    	int ret,tmp;
    	exgcd(x,mod,ret,tmp);
    	return (ret%mod+mod)%mod;
    }
    inline int C(const int &n,const int &m) {
    	return (int64)fac[n]*ifac[m]%mod*ifac[n-m]%mod;
    }
    int main() {
    	const int n=getint(),k=getint();
    	for(register int i=fac[0]=1;i<=n;i++) {
    		fac[i]=(int64)fac[i-1]*i%mod;
    	}
    	ifac[n]=inv(fac[n]);
    	for(register int i=n;i>=1;i--) {
    		ifac[i-1]=(int64)ifac[i]*i%mod;
    	}
    	int ans=0;
    	for(register int i=n,pwr=2;i>=k;i--) {
    		int tmp=(int64)C(n-k,i-k)*(pwr-1)%mod;
    		if((i-k)&1) tmp=mod-tmp;
    		(ans+=tmp)%=mod;
    		pwr=(int64)pwr*pwr%mod;
    	}
    	ans=(int64)ans*C(n,k)%mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Android编译源码过程和重点
    Ubuntu 10.04 下android 源码下载与编译
    Android2.3系统的overscroll效果
    【转】打造人脉不如打造自己
    Android生命周期
    Android Bitmap和Canvas学习笔记
    Android获取手机和系统版本等信息的代码
    Android网络连接处理学习笔记
    Android风格与主题
    Android程序反编译的方法
  • 原文地址:https://www.cnblogs.com/skylee03/p/9661679.html
Copyright © 2020-2023  润新知