[BZOJ2839]集合计数 组合数学+容斥原理

[BZOJ2839]

  • 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007。
  • 垃圾套路题
  • 考虑交集元素个数>=k时,ans=C(n,k)*(2^(2^(n-i)) - 1)
  • 2^(2^(n-i))=2^( 2^(n-i)%(mod-1) ) 费马小定理
  • 直接计算即可
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define o(x) (x&1? -1:1)
using namespace std;
const int mod=1e9+7;
const int N=2e6;
int fact[N],ifact[N],f[N],ans,n,k;
int power(int a,int b,int mod)
{int ans=1;for(;b;b>>=1,a=1LL*a*a%mod)if(b&1)ans=1LL*ans*a%mod;return ans;}
int C(int n,int m){
	return 1LL*fact[n]*ifact[n-m]%mod*ifact[m]%mod;
}
int main()
{
	scanf("%d%d",&n,&k);
	fact[0]=1;rep(i,1,n)fact[i]=1LL*i*fact[i-1]%mod;
	ifact[1]=1;rep(i,2,n)ifact[i]=(mod-1LL*(mod/i)*ifact[mod%i]%mod)%mod;
	ifact[0]=1;rep(i,1,n)ifact[i]=1LL*ifact[i]*ifact[i-1]%mod;
	rep(i,k,n){
		int c=power(2,n-i,mod-1);
		f[i]=1LL*C(n,i)*(power(2,c,mod)-1)%mod;
	}
	rep(i,k,n){
		ans=((ans+1LL*o(i+k)*C(i,k)*f[i]%mod)%mod+mod)%mod;
	}
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/strangeDDDF/article/details/88811880