【BZOJ2839】集合計數 組合數+容斥
阿新 • • 發佈:2017-07-06
什麽 can sample 整數 ips out highlight lag -1
【BZOJ2839】集合計數
Description
一個有N個元素的集合有2^N個不同子集(包含空集),現在要在這2^N個集合中取出若幹集合(至少一個),使得它們的交集的元素個數為K,求取法的方案數,答案模1000000007。(是質數喔~)Input
一行兩個整數N,KOutput
一行為答案。Sample Input
3 2Sample Output
6HINT
【樣例說明】
假設原集合為{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】集合計數 組合數+容斥