bzoj 2839: 集合计数
2839: 集合计数
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 624 Solved: 346
[Submit][Status][Discuss]
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;
Source
二项式反演模板题hhhh
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1000000,ha=1000000007; int jc[maxn+5],ni[maxn+5],n,k,siz[maxn+5],T,ans,f[maxn+5]; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;} inline int ksm(int x,int y,const int M){ int an=1; for(;y;y>>=1,x=x*(ll)x%M) if(y&1) an=an*(ll)x%M; return an;} inline int C(int x,int y){ return x<y?0:jc[x]*(ll)ni[y]%ha*(ll)ni[x-y]%ha;} inline void init(){ jc[0]=1; for(int i=1;i<=maxn;i++) jc[i]=jc[i-1]*(ll)i%ha; ni[maxn]=ksm(jc[maxn],ha-2,ha); for(int i=maxn;i;i--) ni[i-1]=ni[i]*(ll)i%ha; } inline void solve(){ for(int i=k;i<=n;i++) f[i]=C(n,i)*(ll)ksm(2,ksm(2,n-i,ha-1),ha)%ha; for(int i=k;i<=n;i++) if((i-k)&1) ans=add(ans,ha-C(i,k)*(ll)f[i]%ha); else ans=add(ans,C(i,k)*(ll)f[i]%ha); } int main(){ init(),scanf("%d%d",&n,&k); solve(),printf("%d\n",ans); return 0; }
我爱学习,学习使我快乐