###題意:
乙個有n個元素的集合有2
n2^n
2n個不同子集(包含空集),現在要在這2
n2^n
2n個集合中取出若干集合(至少乙個),使得它們的交集的元素個數為k,求取法的方案數,答案模1000000007
###題解:
好題。一開始覺得應該很簡單,然而很快就證明了我很天真。
設f [k
]=cn
k∗∑i
=12n
−kc2
n−ii
=cnk
∗(22
n−k−
1)
f[k]=c_n^k*\sum_^}c_}^i=c_n^k*(2^}-1)
f[k]=c
nk∗
∑i=1
2n−k
c2n
−ii
=cnk
∗(2
2n−k
−1)這個大概就是表示規定選k個,在剩下2n−
k2^
2n−k
個集合中任意選的方案數。
然而這樣算不但有交集大於k的情況,重複的也一大堆。
於是要容斥,考慮容斥係數。
f[k+1]顯然是−ck
+1
k-c_^k
−ck+1k
f[k+2]的第一項是−ck
+2
k-c_^k
−ck+2k
然而多減了f[k+1]的情況,所以要再容斥一下,加上ck+
2k+1
ck+1
kc_^c_^
ck+2k+
1ck
+1k
。根據cnm
cms=
cns∗
cn−s
m−
sc_n^mc_m^s=c_n^s*c_^
cnmcm
s=c
ns∗
cn−s
m−s
最後可以化簡得:g[k
]=∑i
=kn(
−1)n
−ici
kf[i
]g[k]=\sum_^n(-1)^c_^kf[i]
g[k]=i
=k∑n
(−1
)n−i
cik
f[i]
顯然f [i
]=∑j
=inc
jig[
j]
f[i]=\sum_^nc_j^ig[j]
f[i]=∑
j=in
cji
g[j
]直接二項式反演即可
code:
#include#include#include#include#define ll long long
using namespace std;
const ll mod=1000000007;
ll n,k,f[1000010],inv[1000010],t=1,k[1000010];
void pre()
ll pow(ll a,ll b)
return ans;
}ll c(ll n,ll m)
int main()
bzoj2839 集合計數
bzoj許可權題 離線題庫 首先,還是按照這類題目的套路分析 設函式 g x 表示交集至少大小為 x 的方案數 那麼先組合數算選取 x 個數的方法,再對剩下的 n x 個數算集合的集合 也就是集族咯 個數,可以得到 g x 的表示式 g x binom 2 1 那麼我們只要找到乙個容斥函式 f i ...
bzoj2839 集合計數
傳送門 分析 咕咕咕我的做法和這個部落格幾乎相同 只是我在處理 2 1 的時候是先處理前面的再處理後面的 所以前面的 2 我們只需要從 i n 開始迴圈,每次平方即可 include include include include include include include include in...
bzoj2839 集合計數
考慮二項式反演。設 f i 表示交集至少為 i 的方案數,有 f i c n i 2 1 先選 i 必須包含,有 c n i 種選法。包含選出的 i 個元素的集合個數為 2 每個集合都可以選或不選,但是不能乙個也不選,所以方案數為 2 1 之後二項式反演就好了。code includeusing n...