zoukankan      html  css  js  c++  java
  • bzoj 2839 集合计数 容斥广义容斥

    LINK:集合计数

    容斥简单题 却引出我对广义容斥的深思。

    一直以来我都不理解广义容斥是为什么 在什么情况下使用。

    给一张图:

    avatar

    这张图想要表达的意思就是这道题目的意思 而求的东西也和题目一致。

    特点:求出某个集合恰好为k的个数。

    转换:求出集合>=k的个数或者<=k的个数 从而使用广义容斥容斥出来答案。

    关于>=k个数 如上图可见 又很多重复的地方 而广义容斥也是在这么多重复的地方使用的 而并非严格>=k的个数。

    换个说法 >=k的方案数 可能有一些存在重复 但是其特点是>=k 关于这个特点可以利用二进制的子集关系表现出来。

    如 S1,S2都是恰好为k的 他们都能生成S3这个==k+1的集合 此时可以发现 S3被S1生成一次 被S2生成一次。所以所谓的>=k的方案数其中有一部分是子集的互相生成重复。

    广义容斥就是利用这一点来计算的。

    转到题目 不难发现 符合上面定义的>=k方案数为 (C(n,k)(2^{2^{n-k}}-1))

    套广义容斥的式子即可求出答案 值得注意的是 (2^{n-k})可以由欧拉定理%(mod-1).

    这道题还是一个简单容斥的类型。

    可以发现所有的>=k的方案数为 (C(n,k)(2^{2^{n-k}}-1))

    此时讨论 关于选出的k个子集固定时 此时生成的方案除掉这k个交集可能还存在其他交集 -1个交集+2个交集-...

    这样套简单容斥的式子也行。值得注意的是这个讨论实在k个子集固定时的讨论。

    广义容斥 code:

    const ll MAXN=1000010,N=17;
    ll n,k;
    ll fac[MAXN],inv[MAXN];
    inline ll ksm(ll b,ll p,ll pp)
    {
    	ll cnt=1;
    	while(p)
    	{
    		if(p&1)cnt=cnt*b%pp;
    		b=b*b%pp;p=p>>1;
    	}
    	return cnt;
    }
    inline ll C(ll a,ll b){return a<b?0:fac[a]*inv[b]%mod*inv[a-b]%mod;}
    signed main()
    {
    	freopen("1.in","r",stdin);
    	get(n);get(k);fac[0]=1;
    	rep(1,n,i)fac[i]=fac[i-1]*i%mod;
    	inv[n]=ksm(fac[n],mod-2,mod);
    	fep(n-1,0,i)inv[i]=inv[i+1]*(i+1)%mod;
    	ll ans=0;
    	rep(k,n,i)
    	{
    		ans=(ans+(((i-k)&1)?-1:1)*(C(n,i)*(ksm(2,ksm(2,n-i,mod-1),mod)-1))%mod*C(i,k))%mod;
    	}
    	putl((ans+mod)%mod);
    	return 0;
    }
    
  • 相关阅读:
    MapXtreme 2005学习(5):总结查找图元的三种方法
    MapXtreme 2005学习(1):创建临时图层
    MapXtreme 2005学习(2):向图层中添加点
    MapXtreme 2005学习(7):Web页面中实现鼠标中键缩放
    MapXtreme 2005学习(3):向图层中添加线段
    MapXtreme 2005学习(4):添加标注图层
    MapXtreme 2005学习(6):两种方法实现动态轨迹
    JavaScript使用技巧精萃
    C#注释语法
    MapXtreme 2005学习(8):实现手动画线
  • 原文地址:https://www.cnblogs.com/chdy/p/12797898.html
Copyright © 2011-2022 走看看