BZOJ2839集合计数

题目描述

一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得
它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)
题解
假设我们已经确定了这 k个元素都是谁,最后再乘上 C(n,k)就可以了。
根据容斥原理(二项式反演)可知,答案为选出至少 k个的方案数-选出至少 k+1个的方案数+选出至少 k+2个的方案数。。。
如何求选出至少 x个的方案数,考虑有多少种集合包含 x个元素,答案是 2n-x(相当于我们已经确定了 x个元素)。
他们中每个集合都可以选或不选,但是不能都不选。
所以是 2r-1, r是刚才那个 2n-x
最后因为我们固定了k个,有x-k个没有固定,再乘上 C(n-k,x-k)
注意指数要 %mod-1
代码
#include<iostream>
#include<cstdio>
#define N 1000009
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll inv[N],jie[N],ni[N],n,k,ans;
inline ll power(ll x,ll y){
    ll ans=1;
    while(y){
        if(y&1)ans=ans*x%mod;x=x*x%mod;y>>=1;
    }
    return ans;
}
inline ll C(int n,int m){
    return jie[n]*ni[m]%mod*ni[n-m]%mod;
}
int main(){
    cin>>n>>k;
    inv[0]=1;
    for(int i=1;i<=n;++i)inv[i]=inv[i-1]*2%(mod-1);
    jie[0]=1;
    for(int i=1;i<=n;++i)jie[i]=jie[i-1]*i%mod;ni[n]=power(jie[n],mod-2);
    for(int i=n-1;i>=0;--i)ni[i]=ni[i+1]*(i+1)%mod;
    for(int i=k;i<=n;++i){
         if((i-k)&1)ans-=C(n-k,i-k)*(power(2,inv[n-i])-1)%mod;
         else ans+=C(n-k,i-k)*(power(2,inv[n-i])-1)%mod;
         ans=(ans%mod+mod)%mod;
    }
    ans=ans*C(n,k)%mod;
    cout<<ans;
    return 0;
}

转载于:https://www.cnblogs.com/ZH-comld/p/10278257.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值