zoukankan      html  css  js  c++  java
  • bzoj2839

    容斥原理+组合数学

    看见这种恰有k个的题一般都是容斥原理,因为恰有的限制比较强,一般需要复杂度较高的方法枚举,而容斥就是转化为至少有k个,然后通过容斥原理解决

    我们先选出k个元素作为交集,有C(n,k)种可能,那么剩下的n-k个元素既可以选也可以不选,一共有2^(n-k)种选法,每种选法对应了一个集合,也就是说一共有2^(n-k)种不同的集合,我们希望在这n-k个元素中选出若干个集合,使他们的交集为空,于是我们枚举选多少个元素,i=0->n-k,这样有C(n-k,i)种选法,然后我们使用容斥原理来计算i个元素交集为空集的集合数量,对于给定元素交集大小至少为i的情况,我们可以跟刚才一样先选出i个元素作为交集,方案数同上,然后方案数是2^(2^(n-i-k))-1,因为我们有2^(n-i-k)个集合,每个集合可以选或不选,因为已经选出i个元素作为交集,所以交集大小至少是i,其他的集合随便选就满足至少是i

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int N = 1000010, mod = 1000000007;
    int n, k;
    ll ans, pw = 2;
    ll inv[N], fac[N], facinv[N];
    ll C(int n, int k)
    {
        return fac[n] * facinv[k] % mod * facinv[n - k] % mod;
    }
    int main()
    {
        scanf("%d%d", &n, &k);
        inv[0] = inv[1] = fac[0] = fac[1] = facinv[1] = facinv[0] = 1;
        for(int i = 2; i <= n; ++i)
        {
            fac[i] = fac[i - 1] * (ll)i % mod;
            inv[i] = (mod - mod / i) * inv[mod % i] % mod;
            facinv[i] = facinv[i - 1] * inv[i] % mod;
        }
        for(int i = n - k; i >= 0; --i) 
        {
            ans = (((ans + ((i & 1) ? -1 : 1) * C(n - k, i) * ((pw - 1) % mod + mod) % mod) % mod) % mod + mod) % mod;
            pw = pw * pw % mod;     
        }   
        ans = ((ans * C(n, k) % mod) % mod + mod) % mod;
        printf("%lld
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    题解 CF171G 【Mysterious numbers
    题解 P1157 【组合的输出】
    题解 P3955 【图书管理员】
    题解 P2036 【Perket】
    题解 CF837A 【Text Volume】
    题解 CF791A 【Bear and Big Brother】
    题解 CF747A 【Display Size】
    题解 P1332 【血色先锋队】
    题解 P2660 【zzc 种田】
    题解 P4470 【[BJWC2018]售票】
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7695620.html
Copyright © 2011-2022 走看看