[转载]Mr_zkt的集合计数
帮zkt大神存一下题解,他这个超简单的啊:
100%算法2:
首先,选出k个数,用C(n,k)去乘某个东西;
不妨设剩下m个数,则要在这2^m个集合中选出一定数量的集合使得它们的交集为空;
然后容斥就好了
列出式子:
C(n,k)×(sigma{C(m,i)×2^(2^(m-i))}(i从0到m,i为偶)-sigma{C(m,i)×2^(2^(m-i))}(i从0到m,i为奇));
dfs就可以了,中间插一些费马小定理:(2^(m-i)),快速幂:2^(2^(m-i)),逆元(组合数);
预处理出阶乘,逆元;和2的次mi对(1e9+6)取mod;
复杂度O(mlog(1e9+7));
1 #include<cstdio> 2 #include<iostream> 3 #define ll long long 4 #define p1 1000000007 5 #define p2 1000000006 6 #define N 1000009 7 using namespace std; 8 ll n,k,ans,po2[N],m,inc[N],inv[N]; 9 ll po1(ll p) 10 { 11 ll al=1,r=2; 12 for(;p;p>>=1,r=r*r%p1) 13 { 14 if(p&1)al=al*r%p1; 15 } 16 return al; 17 } 18 void dfs(ll g,ll pd) 19 { 20 if(g<0)return; 21 if(pd&1)ans-=inc[m]*inv[pd]%p1*inv[m-pd]%p1*po1(po2[g])%p1; 22 else ans+=inc[m]*inv[pd]%p1*inv[m-pd]%p1*po1(po2[g])%p1; 23 ans%=p1; 24 dfs(g-1,pd+1); 25 } 26 void gcd(ll a,ll b,ll &x,ll &y) 27 { 28 if(!b) 29 { 30 x=1,y=0; 31 return; 32 } 33 gcd(b,a%b,x,y); 34 ll t=x;x=y;y=t-a/b*y; 35 } 36 void init()//m 37 { 38 po2[0]=1; 39 inc[0]=1; 40 inv[0]=1; 41 ll y; 42 for(ll i=1;i<=m;++i) 43 { 44 po2[i]=po2[i-1]*2; 45 po2[i]=po2[i]>=p2?po2[i]-p2:po2[i]; 46 inc[i]=inc[i-1]*i%p1; 47 gcd(inc[i],p1,inv[i],y); 48 inv[i]=(inv[i]+p1)%p1; 49 } 50 for(ll i=m+1;i<=n;++i) 51 { 52 inc[i]=inc[i-1]*i%p1; 53 gcd(inc[i],p1,inv[i],y); 54 inv[i]=(inv[i]+p1)%p1; 55 } 56 } 57 int main() 58 { 59 scanf("%lld%lld",&n,&k); 60 m=n-k; 61 init(); 62 ans=0; 63 dfs(m,0); 64 ans=ans*inc[n]%p1*inv[k]%p1*inv[m]%p1; 65 cout<<(ans+p1)%p1<<endl; 66 67 }
$Fate \ is \ Fake$