zoukankan      html  css  js  c++  java
  • 【bzoj 2839】集合计数

    权限题

    根据广义容斥的套路就很好做了

    (g_i)表示交集至少有(i)个元素,(f_i)表示交集恰好有(i)个元素

    显然有

    [g_i=sum_{j=i}^ninom{j}{i}f_j ]

    二项式反演可得

    [f_i=sum_{j=i}^n(-1)^{j-i}inom{j}{i}g_j ]

    我们求得就是(f_k)

    我们考虑(g)如何求

    我们先从(n)个元素里选择(j)个元素作为我们的交集,这里是(inom{n}{j}),之后对于剩下的(n-j)个元素构成的(2^{n-j})个子集我们从里面任意选择一些,之后并上这(j)个元素就可以了

    于是(g_j=2^{2^{n-j}}),就是(2^{n-j})个子集都可以选或者不选

    记得指数上对(mod-1)取模

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=1000005;
    const LL mod=1000000007;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    LL fac[maxn],inv[maxn],pw[maxn];
    int n,k;
    inline LL ksm(LL a,int b) {
    	LL S=1;
    	while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}
    	return S;
    }
    inline LL C(int n,int m) {
    	if(m>n) return 0;
    	return fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    int main() {
    	n=read(),k=read();
    	fac[0]=1;
    	for(re int i=1;i<=n;i++) fac[i]=(1ll*i*fac[i-1])%mod;
    	inv[n]=ksm(fac[n],mod-2);
    	for(re int i=n-1;i>=0;--i) inv[i]=(1ll*(i+1)*inv[i+1])%mod;
    	pw[0]=1;
    	for(re int i=1;i<=n;i++) pw[i]=(2ll*pw[i-1])%(mod-1);
    	LL ans=0;
    	for(re int i=k;i<=n;i++) {
    		LL g=C(n,i)*ksm(2,pw[n-i])%mod;
    		if((i-k)&1) ans=(ans-C(i,k)*g%mod+mod)%mod;
    			else ans=(ans+C(i,k)*g%mod)%mod;
    	}
    	printf("%d
    ",(int)ans);
    	return 0;
    }
    
  • 相关阅读:
    C#继承
    正则表达式
    C#笔记
    斐波那契数
    out参数
    重载和重写
    数组元素交换位置
    Win10图标显示不正常解决办法
    Linux添加sftp用户并限制其访问目录
    pclzip 解压的文件去掉文件夹
  • 原文地址:https://www.cnblogs.com/asuldb/p/10630880.html
Copyright © 2011-2022 走看看