zoukankan      html  css  js  c++  java
  • 【BZOJ2839】集合计数 容斥原理+组合数

    Description

    一个有N个元素的集合有2N个不同子集(包含空集),现在要在这2N个集合中取出若干集合(至少一个),使得

    它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)

    Input

    一行两个整数N,K

    Output

    一行为答案。

    Sample Input

    3 2

    Sample Output

    6

    HINT

    【样例说明】
    假设原集合为{A,B,C}
    则满足条件的方案为:{AB,ABC},{AC,ABC},{BC,ABC},{AB},{AC},{BC}
    【数据说明】

    对于100%的数据,1≤N≤1000000;0≤K≤N;

    Sol

    恰好xx的问题,很大几率是容斥。。。

    冷静分析一下,我们现在假设钦定了K个数字作为交集的最终结果,那么包含这些数字数字组成的集合就可以随便选,这样的方案数是(C(n,k)*(2^{2^{n-i}}-1))(这里空集是不合法的)。但是这样算出来的是“至少有K个”,我们要用容斥来处理一下,而且这里的方案是有序的,所以容斥系数是还要乘以组合数。具体地,恰好选j个的每个方案里面,都包含了(C(j,i))个有i个的,要算入系数。

    至此本题的解法就完了,但是有一个问题:(2^{2^{n-i}})是不能快速幂的,所以我们用递推法,开始的时候(t=1),每循环一次,(t=t*(t+2))

    Code

    #include <cstdio>
    #define ll long long
    ll n,k,A,fac[1000005],ifc[1000005],inv[1000005],P=1000000007;
    ll c(int x,int y){return 1ll*fac[x]*ifc[y]%P*ifc[x-y]%P;}
    int main()
    {
    	scanf("%lld%lld",&n,&k);
    	inv[1]=fac[0]=ifc[0]=fac[1]=ifc[1]=1;
    	for(int i=2;i<=n;i++) inv[i]=(P-(P/i)*inv[P%i])%P,fac[i]=fac[i-1]*i%P,ifc[i]=ifc[i-1]*inv[i]%P;
    	for(ll i=n,op=((n-k)&1)?-1:1,t=1;i>=k;i--) A=(A+P+op*c(i,k)*c(n,i)%P*t%P)%P,op=-op,t=t*(t+2)%P;
    	printf("%lld
    ",A);
    }
    
  • 相关阅读:
    Aspose.Words三 创建表格
    Aspose.words一 DOM结构
    Aspose.words四 bookmark
    Aspose.Words五 MergeField
    为什么使用Reazor
    C#实现发送给QQ邮件
    T4模板之基础篇
    avalon子孙元素属性监听
    C#设置WebBrowser IE浏览器版本
    【GoLang】GoLang GOPATH 工程管理 最佳实践
  • 原文地址:https://www.cnblogs.com/CK6100LGEV2/p/9415602.html
Copyright © 2011-2022 走看看