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

bzoj2839 集合计数(容斥)

时间:2019-04-27 22:44:46      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:define   --   scan   http   hint   clu   bsp   nbsp   情况   

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 集合计数(容斥)

标签:define   --   scan   http   hint   clu   bsp   nbsp   情况   

原文地址:https://www.cnblogs.com/kafuuchino/p/10780835.html

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