組み合わせの包含と除外をカウントbzoj2839収集回数|問題への解決策

カウントのコレクション

タイトル説明

N個の要素の集合2 ^ N個の異なる部分集合(空集合を含む)があり、今2 ^ N(少なくとも1つ)のこれらの組の数で取り出されるように設定され、例えば、それらの交点Kまでの要素の数すなわち、プログラムの数、応答モード十億七を取得します。(ああ〜は素数です)

入力形式

ライン二つの整数N、K

出力フォーマット

行動の答え。

サンプル

サンプル入力

3 2

サンプル出力

6

データ範囲とヒント

サンプル説明

元のセットは、{A、B、C}であると仮定

条件のための解決策は、満足される:{AB、ABC}、{AC、ABC}、{BC、ABC}、{AB}、{AC}、{BC}

データ説明

データ、1≤N≤1000000の100%、0≤K≤N。

 

 

 

問題の解決策

私たちは、この問題は答えがあると思うのが自然である参照します

C(N、K)* F(NK)

F(i)はi番目の要素2つの表し、Iセットを、任意の数のセットは、交差点の数が空の実施形態になるように選択されるが、セットを選択していませんが合法的ではありません

 

暴力的なアルゴリズム

明らかに、F(0)= 1

提供G(i、j)のkの交点はプログラムの数であるように、任意の数の組が選択され、セットのi番目の要素を表します。

G(i、j)は= C(i、j)は* F(IJ)

I> 1 F(I)のために=コレクション-Σg(i、j)は(j≤i)

22Iのための作品全集-1

ないコレクションが選択されていないことに留意されたいが、要素の集合の任意のセットを選択することができないコレクションのセットを形成するために、位置を伴う-1

Oの複雑さ(N- 2)所望のスコア70

 

正解 容斥原理

F(N)=Σ(-1)iは C(N、I)*(22(NI)-1)(0≤i≤n)を*

ABCは、エミュレートされた一組のA、B、Cを含む交点セットを表します

Cは、(N、I)は、エミュレートされたどのように多くの計算、フォームABCのN個のセットから抽出されたi番目を表します

前記要素のi番目のセットのこの交差点も、この私が含まれています

任意プログラムの数が選択されていない選択ではなく、前記の追加セット後

偶加奇减,则得到全集减去这几个集合的并集,得到f(i)

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 using namespace std;
 5 const int mod=1e9+7;
 6 int n,k;
 7 ll js[1000010],jsinv[1000010];
 8 ll qpow(ll base,int y,int mo)
 9 {
10     ll ans=1;
11     while(y)
12     {
13         if(y&1) ans=ans*base%mo;
14         base=base*base%mo;
15         y>>=1;
16     }
17     return ans;
18 }
19 void init()
20 {
21     js[0]=1;
22     for(int i=1;i<=n;i++) js[i]=js[i-1]*i%mod;
23     jsinv[n]=qpow(js[n],mod-2,mod);
24     for(int i=n-1;i>=0;i--) jsinv[i]=jsinv[i+1]*(i+1)%mod;
25 }
26 inline ll C(int n,int m)
27 {
28     return js[n]*jsinv[m]%mod*jsinv[n-m]%mod;
29 }
30 inline ll ask(int m)
31 {
32     ll ans=0;
33     for(int i=0,u=1;i<=m;i++,u=-u)
34         ans=(ans+u*C(m,i)*(qpow(2,qpow(2,m-i,mod-1),mod)-1)%mod)%mod;
35     return ans;
36 }
37 int main()
38 {
39     scanf("%d%d",&n,&k);
40     init();
41     printf("%lld\n",(ask(n-k)*C(n,k)%mod+mod)%mod);
42     return 0;
43 }
View Code

 

 

 

另一种等价的方法

ans=C(n,k) * ∑(-1)i-k * C(n-k,i-k)*(2ˆ2ˆ(n-i) -1)        (k≤i≤n)

这种方法可以理解为固定一种组合,从其他集合中选取几个进行容斥

也能算出答案

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 using namespace std;
 5 const int mod=1e9+7;
 6 int n,k;
 7 ll js[1000010],jsinv[1000010];
 8 ll qpow(ll base,int y,int mo)
 9 {
10     ll ans=1;
11     while(y)
12     {
13         if(y&1) ans=ans*base%mo;
14         base=base*base%mo;
15         y>>=1;
16     }
17     return ans;
18 }
19 void init()
20 {
21     js[0]=1;
22     for(int i=1;i<=n;i++) js[i]=js[i-1]*i%mod;
23     jsinv[n]=qpow(js[n],mod-2,mod);
24     for(int i=n-1;i>=0;i--) jsinv[i]=jsinv[i+1]*(i+1)%mod;
25 }
26 inline ll C(int n,int m)
27 {
28     return js[n]*jsinv[m]%mod*jsinv[n-m]%mod;
29 }
30 int main()
31 {
32     scanf("%d%d",&n,&k);
33     init();
34     ll ans=0;
35     for(int i=k,u=1;i<=n;i++,u=-u)
36         ans=(ans+u*C(n-k,i-k)%mod*(qpow(2,qpow(2,n-i,mod-1),mod)-1)%mod)%mod;
37     printf("%lld\n",(ans*C(n,k)%mod+mod)%mod);
38     return 0;
39 }
View Code

 

 

おすすめ

転載: www.cnblogs.com/skyh/p/11117919.html