首页 > 代码库 > 【BZOJ2839】集合计数 组合数+容斥
【BZOJ2839】集合计数 组合数+容斥
【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;
题解:容斥,考虑选出若干集合使得交集至少为k的方案数,有$f(i)=C _n^i \times (2^{2^{n-i}}-1)$,可以理解为已经选定了i个,剩下$2^{n-i}$个集合,每个可以选或不选,但是不能一个也不选。但是这样做肯定会有重复的,我们思考容斥系数是什么。
当我们计算交集至少为k的时候,每个交集为j的方案都会被计算$C_j^k$次,所以
f(k)的系数是1
f(k+1)的系数是$-C_{k+1}^k$
f(k+2)的系数$-C_{k+2}^k+C_{k+1}^kC_{k+2}^{k+1}=C_{k+2}^k$(小tips:$C_N^MC_M^S=C_N^SC_{N-S}^{N-M}$)
以此类推,f(i)的系数就是$(-1)^{i-k}C_i^k$。
所以答案为$\sum\limits_{i=k}^n(-1)^{i-k}C_i^kC_n^i(2^{2^{n-i}}-1)$
求组合数需要线性筛逆元,方法:$i^{-1}\equiv\lfloor{p\over i}\rfloor\times(p\%i)^{-1}(\mod p)$
求$(2^{2^i}-1)$可以采用从n到k枚举i的方法,初值tmp=1,然后tmp=tmp*(tmp+2)。
#include <cstdio>#include <cstring>#include <iostream>using namespace std;typedef long long ll;const ll mod=1000000007;ll n,k,ans;ll ine[1000010],jcc[1000010],jc[1000010];ll c(ll x,ll y){ return jc[x]*jcc[y]%mod*jcc[x-y]%mod;}int main(){ scanf("%lld%lld",&n,&k); ll i,j,flag,tmp; ine[1]=jc[1]=jcc[1]=jc[0]=jcc[0]=1; for(i=2;i<=n;i++) { ine[i]=(mod-(mod/i)*ine[mod%i])%mod; jcc[i]=jcc[i-1]*ine[i]%mod; jc[i]=jc[i-1]*i%mod; } for(i=n,flag=((n-k)&1)?-1:1,tmp=1;i>=k;i--) { ans=(ans+mod+flag*c(i,k)*c(n,i)%mod*tmp%mod)%mod; flag=-flag,tmp=tmp*(tmp+2)%mod; } printf("%lld",ans); return 0;}
【BZOJ2839】集合计数 组合数+容斥
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。