bzoj2839: 集合计数

本来是想学二项式反演的怎么我直接容斥就搞出了后面的柿子勒??

首先当组合题做,考虑每一个大小为k的最终交集,那么就有C(n,k)种情况,对于每一种交集,可以选出2^(n-k)种包含这个集合的集合

如果令g(k)=C(n,k)*sigema(1~2^(n-k))i C(2^(n-k),i)的话,这并不是交集大小至少为k的方案数,比如k=1时,集合是{A,B,C},{A}{B}{C}都是一个合法交集,但是选择的时候可以选出3次{A,B,C},所以我们不能直接用最基本的容斥 f(k)=sigema(k~n)i (-1)^(i-k)*g(k)来计算恰好为k的方案数

考虑对于大小为i的集合,对于当前k,它能够产生贡献的次数C(i,k)

于是f(k)=sigema(k~n)i (-1)^(i-k)*g(k)*C(i,k)就可以啦

然后这个就是二项式反演的形式。。。莫名其妙搞出来了。。。

假如从二项式反演的角度思考这个问题,首先我们能求g,然后希望得到的是交集大小为k的方案数f(k)

考虑对于每个交集为i的方案对于g(k)的贡献

和上面的思路几乎一样,因为每个交集为i的方案会被C(i,k)个交集为k的集合转移到

所以g(k)=sigema(k~n)i C(i,k)*f(i)

 

对于具体实现,注意nlogn会被卡,求阶乘逆元的时候可以先把inv[n]算出来再反过来推前面的

考虑如何算g,我们知道C(0,n)+……+C(n,n)=2^n的,可以变成C(n,k)*(2^(2^(n-k))-1)

只需要预处理2^(2^(n-k))

稍微化一下,2^(2^(n-k))=2^(2^(n-k-1)*2)=( 2^(2^(n-k-1)) )^2,这样也可以递推了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>

using namespace std;
typedef long long LL;
const int maxn=1e6+100;
const LL mod=1e9+7;
LL quick_pow(LL A,LL p,LL mo)
{
    LL ret=1;
    while(p!=0)
    {
        if(p%2==1)ret=ret*A%mo;
        A=A*A%mo;p/=2;
    }
    return ret;
}

//---------------------------def----------------------------------------------

LL fac[maxn],fac_inv[maxn];
LL C(int n,int m){return fac[n]*fac_inv[m]%mod*fac_inv[n-m]%mod;}

LL g[maxn],b[maxn];
void solve(int n)
{
    fac[0]=1;fac_inv[0]=1;
    for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    
    fac_inv[n]=quick_pow(fac[n],mod-2,mod);
    for(int i=n-1;i>=1;i--)fac_inv[i]=fac_inv[i+1]*(i+1)%mod;
    
    //......init......
    
    b[n]=2;
    for(int i=n-1;i>=0;i--)b[i]=b[i+1]*b[i+1]%mod;
    for(int i=0;i<=n;i++)
        g[i]=C(n,i)*(b[i]-1)%mod;
}

//---------------------------prepare----------------------------------------------

int main()
{
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    int n,k;
    scanf("%d%d",&n,&k);
    solve(n);
    LL fk=0;
    for(int i=k;i<=n;i++)
        fk=(fk+(((i-k)%2==0)?1:-1)*C(i,k)*
        g[i])%mod;
    printf("%lld\n",(fk+mod)%mod);
    
    return 0;
}

 

posted @ 2019-01-26 10:38  AKCqhzdy  阅读(170)  评论(0编辑  收藏  举报