【组合数学】容斥原理与DeMorgan定理

版权声明:来自达羌蒟蒻 https://blog.csdn.net/PHenning/article/details/89239441

容斥原理

对于对象有重叠的问题,先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
容斥原理的原则:奇加偶减
A B = A + B A B |A\cup B|=|A|+|B|-|A\cap B|

推广: i = 1 n A i = C B ( 1 ) C 1 e C e \Bigg|\bigcup_{i=1}^nA_i\Bigg|=\sum_{C\subseteq B}(-1)^{|C|-1}\Bigg|\bigcap_{e\in C}e\Bigg|

其中 B B 为所有 A i A_i 的集合。

DeMorgan定理

U ( A B ) = ( U A ) ( U B ) U ( A B ) = ( U A ) ( U B ) \complement_U(A\cup B)=(\complement_UA)\cap(\complement_UB)\\\complement_U(A\cap B)=(\complement_UA)\cup(\complement_UB)

推广: U ( i = 1 n A i ) = i = 1 n U A i U ( i = 1 n A i ) = i = 1 n U A i \complement_U\Big(\bigcup_{i=1}^nA_i\Big)=\bigcap_{i=1}^n\complement_UA_i\\\complement_U\Big(\bigcap_{i=1}^nA_i\Big)=\bigcup_{i=1}^n\complement_UA_i

放石子(NKOJ 3495)

问题描述
在一个 m × n m\times n 的矩形网格里放 k k 个相同的石子,问有多少种方法?每个格子最多放一个石子,所有石子都要放完,并且第一行、最后一行、第一列、最后一列都得有石子。

输入格式
三个整数 n , m , k n,m,k

输出格式
一个整数,表示所求方法数。
结果可能很大, m o d    1000007 \mod 1000007 后再输出。

样例输入
2 3 4

样例输出
13

提示
2 n , m 20 , k 500 2\leqslant n,m\leqslant 20,k\leqslant 500

A A 表示第 1 1 行不放石子的方案集合, B B 表示第 m m 行不放石子的方案集合, L L 表示第 1 1 列不放石子的方案集合, R R 表示第 n n 列不放石子的方案集合。设全集为 S S ,答案为在 S S 中而不在 A , B , L , R A,B,L,R 中的所有方案,即
a n s = S A B L R ans=|S|-|A\cup B\cup L\cup R|

然后用容斥原理和组合数计算。式子特别长。

typedef long long LL;
const LL pmod=1000007;
LL C[500][500];
void make_C(LL n){
  for(LL i=0;i<=n;i++)C[i][0]=C[i][i]=1;
  for(LL i=0;i<=n;i++)for(LL j=1;j<i;j++)
    C[i][j]=(C[i-1][j]+C[i-1][j-1])%pmod;
}
int main(){
  LL n,m,k;read(&n,&m,&k);
  make_C(n*m);
  LL S,A,B,L,R,AB,AL,AR,BL,BR,LR,ABL,ABR,ALR,BLR,ABLR,M;
  S=C[n*m][k];
  A=B=C[n*(m-1)][k];
  L=R=C[(n-1)*m][k];
  AB=C[n*(m-2)][k];
  LR=C[(n-2)*m][k];
  AL=AR=BL=BR=C[(n-1)*(m-1)][k];
  ABL=ABR=C[(n-2)*(m-1)][k];
  ALR=BLR=C[(n-1)*(m-2)][k];
  ABLR=C[(n-2)*(m-2)][k];
  M=A+B+L+R-AB-AL-AR-BL-BR-LR+ABL+ABR+ALR+BLR-ABLR;
  write(k?((S-M)%pmod+pmod)%pmod:1,"\n");
  return 0;
}

集合计数(NKOJ 4487)

问题描述
一个有 n n 个元素的集合有 2 n 2^n 个不同子集(包含空集),现在要在这 2 n 2^n 个集合中取出若干集合(至少一个),使得它们的交集的元素个数为 k k ,求取法的方案数,答案模 1000000007 1000000007

输入格式
一行两个整数 n , k n,k

输出格式
一行为答案。

样例输入
3 2

样例输出
6

提示
1 n 1000000 , 0 k n 1\leqslant n\leqslant 1000000,0\leqslant k\leqslant n

先确定交集中的 k k 个元素,方案数为 C n k C_n^k
那么需要在剩余的 n k n-k 个元素里取出若干集合,使得这些集合没有交集。记方案数为 A A
P ( x ) P(x) 为在 x x 元集合中取出若干子集(至少一个)的方案数。(取空集的方案包含在取一个子集的方案内。)
根据定义,
P ( x ) = i = 1 2 x C 2 x i = 2 2 x 1 P(x)=\sum_{i=1}^{2^x}C_{2^x}^i=2^{2^x}-1

i [ 0 , n k ] i\in[0,n-k] C n k i P ( n k i ) C_{n-k}^iP(n-k-i) 就表示在剩余的 n k n-k 个元素里选出若干集合,使得交集中至少有 i i 个元素的方案数。其中 C n k i C_{n-k}^i 确定交集中一定含有的 i i 个元素, P ( n k i ) P(n-k-i) 统计在另外 n k i n-k-i 个元素中选取集合的方案数,在这些集合中各添加确定的 i i 个元素即为所求方案。
根据奇加偶减的原则,
A = i = 0 n k ( 1 ) i C n k i P ( n k i ) = i = 0 n k ( 1 ) i C n k i ( 2 2 n k i 1 ) \begin{aligned} A&amp;=\sum_{i=0}^{n-k}(-1)^iC_{n-k}^iP(n-k-i)\\ &amp;=\sum_{i=0}^{n-k}(-1)^iC_{n-k}^i(2^{2^{n-k-i}}-1) \end{aligned}

所以
a n s = C n k A = C n k i = 0 n k ( 1 ) i C n k i ( 2 2 n k i 1 ) ans=C_n^kA=C_n^k\sum_{i=0}^{n-k}(-1)^iC_{n-k}^i(2^{2^{n-k-i}}-1)

typedef long long LL;
const LL pmod=1000000007;
const int maxn=1000000;
LL C[maxn];
LL Pow(LL a,LL b,LL c){
  LL ans=1;a=a%c;
  while(b){
    if(b%2)ans=(ans*a)%c;
    b=b/2,a=(a*a)%c;
  }
  return ans;
}
void make_Cn(LL n){
  C[0]=1,C[1]=n;
  for(LL i=2;i<=n;i++)
    C[i]=((C[i-1]*(n-i+1))%pmod*Pow(i,pmod-2,pmod))%pmod;
}
int main(){
  LL n,k,ans,t=0;read(&n,&k);
  make_Cn(n);ans=C[k];
  make_Cn(n-k);
  for(LL i=0;i<=n-k;i++)
    t=(t+(((i&1?-1:1)*C[i])%pmod*(Pow(2,Pow(2,n-k-i,pmod-1),pmod)-1))%pmod+pmod)%pmod;
  ans=(ans*t)%pmod;
  write(ans,"\n");
  return 0;
}

猜你喜欢

转载自blog.csdn.net/PHenning/article/details/89239441