zoukankan      html  css  js  c++  java
  • 【BZOJ2839】集合计数(广义容斥)

    点此看题面

    • 一个(n)个元素的集合有(2^n)个不同的子集。
    • 要求从这些子集中选出至少一个集合,使得选出集合的交集大小恰好为(k),求方案数。
    • (nle10^6)

    广义容斥

    对于这种恰好为(k)的显然想到容斥,去设(f_i)为交集大小大于等于(i)的方案数,根据广义容斥的式子就可以发现:

    [ans=sum_{i=k}^n(-1)^{k-i}C_i^kf_i ]

    于是只要考虑如何快速计算(f_i),首先有个选出(i)个数的方案数(C_n^i)

    那么选出的所有集合都必须包含这(i)个数,剩下(n-i)个数可以任选,因此总共有(2^{n-i})个包含这(i)个数的集合。

    然后我们可以在这些集合中选出至少一个,最终得到:

    [f_i=C_n^i imes 2^{2^{n-i}}-1 ]

    此时已经可以(O(logn))计算每个(f_i)了,但事实上我们可以发现:

    [2^{2^{n-i}}=2^{2^{n-i-1} imes 2}=(2^{2^{n-(i+1)}})^2 ]

    所以我们只要维护(2^{2^{n-i}})并从大到小枚举(i),便可实现(O(n))了。

    代码:(O(n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000000
    #define X 1000000007
    #define C(x,y) (1LL*Fac[x]*IFac[y]%X*IFac[(x)-(y)]%X)//组合数
    using namespace std;
    int n,k,Fac[N+5],IFac[N+5];
    I int QP(RI x,RI y,CI p) {RI t=1;W(y) y&1&&(t=1LL*t*x%p),x=1LL*x*x%p,y>>=1;return t;}
    int main()
    {
    	RI i,p;for(scanf("%d%d",&n,&k),Fac[0]=i=1;i<=n;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理阶乘
    	for(IFac[i=n]=QP(Fac[n],X-2,X);i;--i) IFac[i-1]=1LL*IFac[i]*i%X;//预处理阶乘逆元
    	long long t=0;for(p=2,i=n;i>=k;p=1LL*p*p%X,--i) t+=((i-k)&1?X-1LL:1LL)*C(i,k)%X*C(n,i)%X*(p-1)%X;//广义容斥
    	return printf("%d
    ",(t%X+X)%X),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    mysql报错:java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone.
    MD5登陆密码的生成
    15. 3Sum、16. 3Sum Closest和18. 4Sum
    11. Container With Most Water
    8. String to Integer (atoi)
    6. ZigZag Conversion
    5. Longest Palindromic Substring
    几种非线性激活函数介绍
    AI初探1
    AI初探
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ2839.html
Copyright © 2011-2022 走看看