• 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
  • 相关阅读:
    发布一个扩展Repeater的模板控件,带自动分页功能
    webservice 测试窗体只能用于来自本地计算机的请求
    FCKeditor编辑器中设置默认文本行高和字体大小
    程序员的个人性格
    程序设计模式的有趣解释-追MM
    集锦一
    UML简介(原创)
    一位IT从业人员的心路历程
    一个初级测试工程师的工作总结
    "与熊共舞"(转载)
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7695620.html
Copyright © 2020-2023  润新知