码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj2839]集合计数题解(容斥)

时间:2020-08-01 15:48:20      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:include   关系   mit   ==   输入格式   mat   inline   ali   方法   

题目描述

一个有\(N\)个元素的集合有\(2^N\)个不同子集(包含空集),现在要在这\(2^N\)个集合中取出若干集合(至少一个),使得
它们的交集的元素个数为\(K\),求取法的方案数,答案模\(1e9+7\)

输入格式

一行两个整数\(N,K\)

输出格式

一行为答案。

对于\(100\)%的数据,\(1≤N≤1000000\)\(0≤K≤N\)

$ (TimeLimit:1s,MemoryLimit:128M)$

思路

我们首先确定我们交集所包含的\(k\)个元素,一共有\(\binom{n}{k}\)种方法。

假定我们当前确定的包含\(k\)个的元素的集合为\(S\)

那么包含\(S\)的子集相当于在除了\(S\)包括的元素中,选任意多元素的元素凑成的子集。

那么包含\(S\)的所有子集有

\[\sum_{i=0}^{n-k}\binom{n-k}{i}=2^{n-k} \]

从中选任意多个集合相交共有

\[\sum_{i=1}^{2^{n-k}}\binom{2^{n-k}}{i}=\sum_{i=0}^{2^{n-k}}\binom{2^{n-k}}{i}-\binom{2^{n-k}}{0}=2^{2^{n-k}}-1 \]

种方案

但是这样算是所有交集大于等于\(k\)个元素的方案,即除了\(S\)还有其他的交集。

那么我们就要把其中所有交集大小大于\(k\)个元素的方案给减掉。

所有交集大小大于\(k\)个元素的方案等价于所有交集大小大于等于\(k+1\)个元素的方案。

我们当前的方案已经确定了包含\(k\)个元素的集合\(S\),那么我们只需要在除了\(S\)的元素中任选一个即可凑成一个包含\(k+1\)个元素的集合,设除了\(S\)以外的元素为\(a\),那么我们就可以用上面的方法算出交集至少为\(S,a\)的方案数。其中\(a\)共有\(\binom{n-k}{1}\)种选法。

那么是否我们直接减去

\[\binom{n-k}{1}(2^{2^{n-k-1}}-1) \]

就是交集恰好为\(S\)的方案数呢?

考虑下面的情况:

{\(Sabcd,Sabcf\)}

交集为\(Sabc\)

而当我们确定交集至少为\(Sa,Sb,Sc\)都可以凑成这种方案,也就会产生重复计数导致答案变小。

我们设\(P_a\)为交集除了包括\(S\),还需包括\(a\)的集合。

那么我们要求的是一个并集的关系,即

\[\left|\bigcup P \right| \]

我们考虑任意两个方案集合\(P_a\)\(P_b\)的交集

\[\left|P_a \bigcap P_b \right| \]

考虑其意义,即满足交集至少包含\(S\)\(a\)\(b\)的方案。

那么有

\[\left|P_a \bigcap P_b \right|=(2^{2^{n-k-2}}-1) \]

其方案集合交集的大小只与相交集合的个数有关,与具体是哪几个相交无关。

\(P\)集合一共有\(n-k\)

那么有

\[\left|\bigcup P \right|=\sum_{i=1}^{n-k}\binom{n-k}{i}(-1)^{j-1}(2^{2^{n-k-i}}-1) \]

那么确定交集为\(k\)个元素的方案数为

\[\begin{aligned} (2^{2^{n-k}}-1)-\left|\bigcup P \right|&=(2^{2^{n-k}}-1)-\sum_{i=1}^{n-k}\binom{n-k}{i}(-1)^{j-1}(2^{2^{n-k-i}}-1)\&=(2^{2^{n-k}}-1)+\sum_{i=1}^{n-k}\binom{n-k}{i}(-1)^{j}(2^{2^{n-k-i}}-1)\&=\sum_{i=0}^{n-k}\binom{n-k}{i}(-1)^{j}(2^{2^{n-k-i}}-1) \end{aligned} \]

那么答案为

\[\binom{n}{k}\times \sum_{i=0}^{n-k}\binom{n-k}{i}(-1)^{j}(2^{2^{n-k-i}}-1) \]

那么不同的两个交集\(S\)\(A\)之间的方案是否会有冲突?

那么显然是不会的,在我们上面的计算中,可以确保我们每种选\(k\)个元素的方案的交集一定是交集恰好为\(S\)\(A\)的。

代码

#include <iostream>

using namespace std;

const int N = 1e6 + 10,mod = 1e9 + 7;

long long fac[N],invfac[N],two[N];

int C(int n,int m){return n<m?0:(long long)fac[n]*invfac[m]%mod*invfac[n-m]%mod;}

inline void init(){
    fac[0]=invfac[0]=invfac[1]=1;
    for(int i=1;i<=N - 10;i++)fac[i]=(long long)fac[i-1]*i%mod;
    for(int i=2;i<=N - 10;i++)invfac[i]=(long long)(mod-mod/i)*invfac[mod%i]%mod;
    for(int i=2;i<=N - 10;i++)invfac[i]=(long long)invfac[i-1]*invfac[i]%mod;
    two[0] = 2;
    for (int i = 1; i <= N - 10; i++){
        two[i] = two[i - 1] * two[i - 1] % mod;
    }
}

int main(){
    init();
    int n,k;
    cin >> n >> k;
    long long ans = 0;
    for (int i = 0;i <= n - k; i++){
        if ((i % 2) == 0) ans = (ans + C(n-k,i) * (two[n - k - i] - 1) % mod) % mod;
        else ans = (ans - C(n-k,i) * (two[n - k - i] - 1) % mod + mod) % mod; 
    }
    cout << C(n,k) * ans % mod;
    return 0;
}

[bzoj2839]集合计数题解(容斥)

标签:include   关系   mit   ==   输入格式   mat   inline   ali   方法   

原文地址:https://www.cnblogs.com/wxy-max/p/13414498.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!