【bzoj 2839】集合計數
阿新 • • 發佈:2019-03-31
isp 元素 bzoj cpp code 做了 ret 套路 集合
權限題
根據廣義容斥的套路就很好做了
設\(g_i\)表示交集至少有\(i\)個元素,\(f_i\)表示交集恰好有\(i\)個元素
顯然有
\[g_i=\sum_{j=i}^n\binom{j}{i}f_j\]
二項式反演可得
\[f_i=\sum_{j=i}^n(-1)^{j-i}\binom{j}{i}g_j\]
我們求得就是\(f_k\)
我們考慮\(g\)如何求
我們先從\(n\)個元素裏選擇\(j\)個元素作為我們的交集,這裏是\(\binom{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\n",(int)ans); return 0; }
【bzoj 2839】集合計數