[转载]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 }
超棒的

 

posted @ 2019-06-28 15:36  DeepinC  阅读(254)  评论(0编辑  收藏  举报