1. 程式人生 > >bzoj2839 集合計數(容斥)

bzoj2839 集合計數(容斥)

problem int color com href 包含 turn 質數 space

2839: 集合計數

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 883 Solved: 490
[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


這若幹個集合的交集的方案數:$C(n,k)$

那麽問題就轉化成:對剩下的$m=n-k$個數,求集合取法,使它們之間沒有交集

這種計數問題一般用容斥瞎搞

先求出$m$個數構成的集合的所有取法:$2^{2^{m}}-1$

共$2^{m}$個集合,每個集合可取可不取$(2^{2^{m}})$,再減去一個都不取的情況$(-1)$

藍後我們把交集$>=1$的取法減掉

#include<iostream>//註意防爆int
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
#define N 1000005
const ll P=1000000007;
int n,k,m;ll ans,nw,inv[N],fac[N],ifac[N];
inline ll C(int a,int b){return fac[a]*ifac[b]%P*ifac[a-b]%P;}
int main(){
    scanf(
"%d%d",&n,&k); inv[1]=1; fac[0]=fac[1]=ifac[0]=ifac[1]=1; for(int i=2;i<=n;++i){ inv[i]=1ll*(P-P/i)*inv[P%i]%P; fac[i]=fac[i-1]*i%P; ifac[i]=ifac[i-1]*inv[i]%P; }m=n-k;nw=2; for(int i=m;i>=0;--i,nw=nw*nw%P) ans=((ans+((i&1)?-1:1)*C(m,i)%P*(nw-1)%P)%P+P)%P; ans=ans*C(n,k)%P; printf("%lld",ans); return 0; }

bzoj2839 集合計數(容斥)