集合计数 count

题意简述:一个有n个元素的集合有 2n 个不同子集(包含空集),现在要在这 2n 个集合中取出若干集合(至少一个),使得它们的交集的元素个数为 K ,求取法的方案数,答案模1000000007。(1N1000000,0KN)
题解:任意选 k 个最终交集,有Ckn种取法,现在考虑已经固定了交集的 k 个元素,那么剩下的nk个元素选出的集合有 K=2nk 种取法,这些集合中取出的集合有 2K1 中取法,这些集合取法中包含了交集大于 k 个元素,容斥一下,减掉交集为k+1的,加上交集为 k+2 的,以此类推。

#include<bits/stdc++.h>
typedef long long ll;
const int N = 1e6 + 50;
const int P = 1000000007;
ll fac[N],inv[N],f[N];
ll ksm(ll x, int k){
    ll ans = 1;
    for (; k; k>>=1,x = x * x % P)
        if (k & 1) ans = ans * x % P;
    return ans;
}
void init(int n){
    fac[0] = 1;
    for (int i=1; i<=n; i++)
        fac[i] = fac[i - 1] * i % P;
    inv[n] = ksm(fac[n],P - 2);
    for (int i=n-1; i>=0; i--)
        inv[i] = inv[i + 1] * (i + 1) % P;
}
ll c(int n, int k){
    return fac[n] * inv[k] % P * inv[n - k] % P;
}
ll solve(int n, int k){
    f[n] = 2;
    for (int i=n-1; i>=k; i--)
        f[i] = f[i + 1] * f[i + 1] % P;
    ll ans = 0;
    for (int i=k,F=1; i<=n; i++,F*=-1)
        ans = (ans + c(n-k,i-k) * (f[i] - 1) * F) % P;
    return (ans * c(n,k) % P + P) % P;
}
int main(){
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    int n,k;
    scanf("%d%d",&n,&k);
    init(n);
    printf("%lld\n",solve(n,k));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值