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;
    }
    
  • 相关阅读:
    Java实现HttpClient发送GET、POST请求(https、http)
    解决.net core 3.1 json日期带T的问题
    Java验证身份证号码的格式
    c++20新特性concept
    位图
    Linux内核 hlist_head/hlist_node结构解析
    linux将c++程序制作成.deb
    应用程序或动态库中与加载的其他动态库的类或者函数重名问题
    vue props 属性值接受多个类型
    异步循环
  • 原文地址:https://www.cnblogs.com/chdy/p/12797898.html
Copyright © 2011-2022 走看看