acm-排列组合学习笔记(更新中)

引言

本文主要介绍排列与组合的相关知识点,以及重要的一些结论推论及其证明,会给出少量的例题,此外本文是建立在作者的需求上,故更多简单的内容不会涉及,默认读者已经拥有前置技能,本文还在更新中。。。

排列组合

  • 引言
  • 一、集合
    • 1.不可重集
      • (1).普通排列
    • (2).圆排列
      • (3).组合
    • 2.可重集
      • (1).排列
        • [1].无限集
        • [2].有限集
      • (2).组合
        • [1].无限集
        • [2].有限集
  • 二、组合数(二项式系数)
    • 1.二项式定理
      • (1).基本内容
      • (2).推广
    • 2. 帕斯卡三角形
    • 3.组合数性质
    • 4.组合数取模及求解
      • (1).Pascal打表法(批量)
      • (2).公式法(单个)
        • [1].方法一
        • [2].方法二
        • [3].方法三
      • (3).卢卡斯定理
      • (4).扩展卢卡斯
  • 三、特殊排列组合
    • 1.不相邻组合
    • 2.错排列
  • 四、康托展开
    • 1.基本内容
    • 2.康拓展开代码实现
    • 3.逆康托展开
    • 4.逆康拓展开代码实现
  • 五、卡特兰数
    • 1.定义
    • 2.性质
    • 3.常用模型
    • 4.卡特兰数延伸-非降路径数统计
    • 5.习题
  • 六、容斥原理
  • 七、贝尔数
  • 八、伯努利数
  • 九、斯特林数
  • 十、母函数
  • 十一、递推
  • 十二、polya计数

一、集合

前置规定:

  1. 0 ! = 1 0!=1 0!=1
  2. m > n m>n m>n时有 C n m = A n m = 0 C_n^m=A_n^m=0 Cnm=Anm=0

1.不可重集

(1).普通排列

从有 n n n个元素的不可重集中选则 k k k个元素排成一个序列的方案记为 A n k A_n^k Ank
其中 A n k = n ( n − 1 ) ( n − 2 ) . . . . ( n − k + 1 ) = n ! ( n − k ) ! A_n^k=n(n-1)(n-2)....(n-k+1)={n!\over (n-k)!} Ank=n(n1)(n2)....(nk+1)=(nk)!n!

证明:考虑从集合中一个一个拿出元素,第一次有 n n n种选择,第二次有 n − 1 n-1 n1种选择,…,第 k k k次有 n − k + 1 n-k+1 nk+1种选择,根据乘法原理我们有 A n k = n ( n − 1 ) ( n − 2 ) . . . ( n − k + 1 ) A_{n}^k=n(n-1)(n-2)...(n-k+1) Ank=n(n1)(n2)...(nk+1)

(2).圆排列

从有 n n n个元素的不可重集中选择 k k k个元素排成一个环的总方案数为 A n k k = n ! k ( n − k ) ! {A_n^k\over k}={n!\over k(n-k)!} kAnk=k(nk)!n!

证明:如果想要构成环,我们可以先从集合中取 k k k个元素排成一个序列,然后再把序列首位相接即可,对于一个圆排列而言,如果把它拆成一个序列有 k k k种拆法,对应是 k k k个不同的序列,因此序列的排列数是圆的排列数的 k k k倍,故命题正确。

(3).组合

n n n个元素的不可重集中选择 k k k个元素的方案数记为 C n k C_n^k Cnk(现在更记作 ( n k ) \binom{n}{k} (kn),读作 n n n k k k ),其中 C n k = A n k k ! = n ! k ! ( n − k ) ! C_n^k={A_n^k\over k!}={n!\over k!(n-k)!} Cnk=k!Ank=k!(nk)!n!

证明:从不可重集中选择 k k k个元素的方式可以拆分为先从集合中选择 k k k个元素构成一个排列,方案数有 A n k A_n^k Ank,但是同一个选择元素的方案会对应有 k ! k! k!种排列,故选择的方案为 A n k k ! 。 {A_n^k\over k!}。 k!Ank

2.可重集

(1).排列

[1].无限集

从含有 n n n种元素的无限可重集(每种元素都有无限个)中选出 k k k个元素构成排列的方案数为 n k n^k nk

证明:取元素的过程中每次都有 n n n种选择,故总共有 n ⋅ n ⋯ n ( k 个 n ) = n k n\cdot n\cdots n(k个n)=n^k nnn(kn)=nk种方案。

推广:如果每种元素的个数至少为 k k k则命题依然成立。

[2].有限集

假设 k k k种元素的有限集中的元素的个数分别为 n 1 , n 2 , . . . , n k n_1,n_2,...,n_k n1,n2,...,nk,且 n = n 1 + n 2 + . . . + n k n=n_1+n_2+...+n_k n=n1+n2+...+nk,则该集合的全排列数记作 ( n n 1 , n 2 , . . . , n k ) \binom{n}{n_1,n_2,...,n_k} (n1,n2,...,nkn),它实际上等于 n ! n 1 ! n 2 ! . . . n k ! {n!\over n_1!n_2!...n_k!} n1!n2!...nk!n!

证明:如果这是 n n n个不同的元素那么全排列就等于 n ! n! n!,但是里面存在重复的元素,因此需要去重,对于同一个排列而言第 i i i种元素会重复 n i ! n_i! ni!次,因此需要除去,故原命题成立。

(2).组合

[1].无限集

n n n种元素的无限集(每种元素无限个)中选择 k k k个元素的方案数为 ( n + k − 1 k ) = ( n + k − 1 n − 1 ) \binom{n+k-1}{k}=\binom{n+k-1}{n-1} (kn+k1)=(n1n+k1)

证明:假设第 i i i种元素选择 x i x_i xi个,于是有 x 1 + x 2 + . . . + x n = k x_1+x_2+...+x_n=k x1+x2+...+xn=k,其中 x i ≥ 0 , ∀ i ∈ [ 1 , n ] x_i\ge 0,\forall i\in[1,n] xi0,i[1,n]。考虑令 y i = x i + 1 , ∀ i ∈ [ 1 , n ] y_i=x_i+1,\forall i\in[1,n] yi=xi+1,i[1,n],于是有 y 1 + y 2 + . . . + y n = n + k y_1+y_2+...+y_n=n+k y1+y2+...+yn=n+k,然后思考这些 y y y的取值组合有多少种,我们可以把它转化为隔板模型:有 n + k n+k n+k个小球放在盒子里,然后要在这些小球之间的 n + k − 1 n+k-1 n+k1个缝隙中插入 n − 1 n-1 n1个隔板,因此有 ( n + k − 1 n − 1 ) \binom{n+k-1}{n-1} (n1n+k1)种方案数。

[2].有限集

假设 k k k种元素的有限集中的元素的个数分别为 n 1 , n 2 , . . . , n k n_1,n_2,...,n_k n1,n2,...,nk,且 n = n 1 + n 2 + . . . + n k n=n_1+n_2+...+n_k n=n1+n2+...+nk,则从该集合中选择 r r r个元素的方案数为 ∑ i = 0 k ( − 1 ) k ∑ ∣ A ∣ = i ( k + r − ∑ j = 1 i n A j − i − 1 k − 1 ) \sum_{i=0}^k(-1)^k\sum_{|A|=i}\tbinom{k+r-\sum_{j=1}^{i}n_{A_j}-i-1}{k-1} i=0k(1)kA=i(k1k+rj=1inAji1),其中 A A A代表 { 1 , 2 , . . . , k } \{1,2,...,k\} {1,2,...,k}的子集, A j A_j Aj代表集合 A A A的第 j j j个元素。

证明:考虑容斥原理(见第六部分),设第 i i i种元素选择 x i x_i xi个,则满足 x 1 + x 2 + . . . + x k = r , ∀ i ∈ [ 1 , k ] , x i ≤ n i x_1+x_2+...+x_k=r,\forall i\in[1,k],x_i\le n_i x1+x2+...+xk=r,i[1,k],xini,在保证 x i ≥ 0 , ∀ i ∈ [ 1 , k ] x_i\ge 0,\forall i\in[1,k] xi0,i[1,k]的前提条件下我们不妨设我们要求解的方案数 ∣ S ∣ = ∣ { x 1 ≤ n 1 ∧ x 2 ≤ n 2 ∧ . . . ∧ x k ≤ n k ∧ ∑ i = 1 k x i = r } ∣ |S|=|\{x_1\le n_1 \land x_2 \le n_2\land ...\land x_k\le n_k \land \sum_{i=1}^kx_i=r\}| S={x1n1x2n2...xknki=1kxi=r},设方案 S i = { x i ≤ n i ∧ ∑ j = 1 k x j = r } , S i ‾ = { x i ≥ n i + 1 ∧ ∑ j = 1 k x j = r } } S_i=\{x_i\le n_i\land \sum_{j=1}^kx_j=r\},\overline{S_i}=\{x_i\ge n_i+1\land \sum_{j=1}^kx_j=r\}\} Si={xinij=1kxj=r},Si={xini+1j=1kxj=r}},设全集 U = { ∑ i = 1 k x i = r } U=\{\sum_{i=1}^kx_i=r\} U={i=1kxi=r},那么显然有 ∣ S ∣ = ∣ U ∣ − ∣ ∪ i = 1 k S i ‾ ∣ |S|=|U|-|\cup_{i=1}^k\overline{S_i}| S=Ui=1kSi,现在考虑如何求解 ∣ ∪ i = 1 k S i ‾ ∣ |\cup_{i=1}^k\overline{S_i}| i=1kSi
根据前置定理 ∣ S i ‾ ∣ = ( k + r − n i − 2 k − 1 ) |\overline{S_i}|=\tbinom{k+r-n_i-2}{k-1} Si=(k1k+rni2)(参考第一部分2.(2).[1])
我们有如下等式成立:
∣ ∪ i = 1 k S i ‾ ∣ = ∑ i = 1 k ∣ S i ‾ ∣ − ∑ 1 ≤ i 1 < i 2 ≤ k ∣ S i 1 ‾ ∩ S i 2 ‾ ∣ + ∑ 1 ≤ i 1 < i 2 < i 3 ≤ k ∣ S i 1 ‾ ∩ S i 2 ‾ ∩ S i 3 ‾ ∣ + . . . + ( − 1 ) k − 1 ∣ ∩ i = 1 k S i ‾ ∣ = ∑ i = 1 k ( k + r − n i − 2 k − 1 ) − ∑ 1 ≤ i 1 < i 2 ≤ k ( k + r − n i 1 − n i 2 − 3 k − 1 ) + . . . + ( − 1 ) k − 1 ( k + r − ∑ i = 1 k n i − k − 1 k − 1 ) = ∑ i = 1 k ( − 1 ) i − 1 ∑ ∣ A ∣ = i ( k + r − ∑ j = 1 i n A j − i − 1 k − 1 ) \begin{aligned} |\cup_{i=1}^k\overline{S_i}|&=\sum_{i=1}^k |\overline{S_i}|-\sum_{1\le i_1i=1kSi=i=1kSi1i1<i2kSi1Si2+1i1<i2<i3kSi1Si2Si3+...+(1)k1i=1kSi=i=1k(k1k+rni2)1i1<i2k(k1k+rni1ni23)+...+(1)k1(k1k+ri=1knik1)=i=1k(1)i1A=i(k1k+rj=1inAji1)
于是我们有 ∣ S ∣ = ∣ U ∣ − ∣ ∪ i = 1 k S i ‾ ∣ = ∑ i = 0 k ( − 1 ) k ∑ ∣ A ∣ = i ( k + r − ∑ j = 1 i n A j − i − 1 k − 1 ) |S|=|U|-|\cup_{i=1}^k\overline{S_i}|=\sum_{i=0}^k(-1)^k\sum_{|A|=i}\tbinom{k+r-\sum_{j=1}^{i}n_{A_j}-i-1}{k-1} S=Ui=1kSi=i=0k(1)kA=i(k1k+rj=1inAji1)成立。

二、组合数(二项式系数)

1.二项式定理

(1).基本内容

( a + b ) n = ∑ i = 0 n C n i a i b n − i = ∑ i = 0 n ( n i ) a i b n − i , 其 ∑ i = 0 n ( n i ) = 2 n (a+b)^n=\sum_{i=0}^nC_n^ia^ib^{n-i}=\sum_{i=0}^n\tbinom{n}{i}a^ib^{n-i},其\sum_{i=0}^n\tbinom{n}{i}=2^n (a+b)n=i=0nCniaibni=i=0n(in)aibnii=0n(in)=2n

证明:由于 ( a + b ) n = ( a + b ) ( a + b ) . . . ( a + b ) , ( n 个 ( a + b ) ) (a+b)^n=(a+b)(a+b)...(a+b),(n个(a+b)) (a+b)n=(a+b)(a+b)...(a+b),(n(a+b)),根据展开式的展开过程我们知道只需要从每个 ( a + b ) (a+b) (a+b)中选择一个 a a a b b b然后乘起来就得到了最终的结果,因此我们有每一项 a x b y a^xb^y axby满足 x + y = n x+y=n x+y=n,考虑有多少个 a i b n − i a^ib^{n-i} aibni,显然我们只需要从 n n n ( a + b ) (a+b) (a+b)中选出 i i i a a a,剩下的即是 b b b,故总方案数为 C n i C_n^i Cni,故 ( a + b ) n = ∑ i = 0 n C n i a i b n − i (a+b)^n=\sum_{i=0}^nC_n^ia^ib^{n-i} (a+b)n=i=0nCniaibni

还可以利用归纳法证明,用公式 C n i − 1 + C n i = C n + 1 i C_n^{i-1}+C_n^i=C_{n+1}^i Cni1+Cni=Cn+1i来证明(比较简单就不证了)。

此外如果我们令 a = 1 , b = 1 a=1,b=1 a=1,b=1就能得到 ∑ i = 0 n ( n i ) = 2 n \sum_{i=0}^n\tbinom{n}{i}=2^n i=0n(in)=2n

(2).推广

二项式定理可以推广为多项式形式:
( ∑ i = 1 k x i ) n = ∑ n 1 + n 2 + . . . + n k = n ( n n 1 , n 2 , . . . , n k ) x 1 n 1 x 2 n 2 . . . x k n k , 其 中 ∑ n 1 + n 2 + . . . + n k = n ( n n 1 , n 2 , . . . , n k ) = k n (\sum_{i=1}^kx_i)^n=\sum_{n_1+n_2+...+n_k=n}\tbinom{n}{n_1,n_2,...,n_k}x_1^{n_1}x_2^{n_2}...x_k^{n_k},其中\sum_{n_1+n_2+...+n_k=n}\tbinom{n}{n_1,n_2,...,n_k}=k^n (i=1kxi)n=n1+n2+...+nk=n(n1,n2,...,nkn)x1n1x2n2...xknk,n1+n2+...+nk=n(n1,n2,...,nkn)=kn

证明:实际上二项式定理可以写成 ( ∑ i = 1 2 x i ) n = ∑ n 1 + n 2 = n ( n n 1 , n 2 ) x 1 n 1 x 2 n 2 (\sum_{i=1}^2x_i)^n=\sum_{n_1+n_2=n}\tbinom{n}{n_1,n_2}x_1^{n_1}x_2^{n_2} (i=12xi)n=n1+n2=n(n1,n2n)x1n1x2n2,类比过去即可。不过要严谨证明的话也是同样的两种方式:
一是考虑它的组合学意义,我们首先确定 x 1 , x 2 , . . . , x k x_1,x_2,...,x_k x1,x2,...,xk它们的幂次,也就是 n 1 , n 2 , . . . , n k n_1,n_2,...,n_k n1,n2,...,nk,要得到它们这意味着我们要对每个括号(即 ( x 1 + x 2 + . . . x k ) (x_1+x_2+...x_k) (x1+x2+...xk))选择一个 x i , i = 1 , 2 , . . . , k x_i,i=1,2,...,k xi,i=1,2,...,k,这相当于我们对 n 1 ∗ x 1 , n 2 ∗ x 2 , . . . , n k ∗ x k n_1*x_1,n_2*x_2,...,n_k*x_k n1x1,n2x2,...,nkxk( n i ∗ x i n_i*x_i nixi代表 n i n_i ni x i x_i xi),进行排序,然后按顺序映射到每个括号,那么有多少种排序方式呢?根据一.2.(1).[2]我们知道有限可重集的全排列为 ( n n 1 , n 2 , . . . , n k ) \tbinom{n}{n_1,n_2,...,n_k} (n1,n2,...,nkn),故命题成立。

二是数学归纳法,这里不做证明,感兴趣的可以去网上搜索相关资料。

此外如果我们令 x i = 1 , ∀ i ∈ [ 1 , k ] x_i=1,\forall i\in[1,k] xi=1,i[1,k]就能得到 ∑ n 1 + n 2 + . . . + n k = n ( n n 1 , n 2 , . . . , n k ) = k n \sum_{n_1+n_2+...+n_k=n}\tbinom{n}{n_1,n_2,...,n_k}=k^n n1+n2+...+nk=n(n1,n2,...,nkn)=kn

2. 帕斯卡三角形

帕斯卡三角形如下表所示:

n/k 0 1 2 3 4 5 6 7 8
0 1
1 1 1
2 1 2 1
3 1 3 3 1
4 1 4 6 4 1
5 1 5 10 10 5 1
6 1 6 15 20 15 6 1
7 1 7 21 35 35 21 7 1
8 1 8 28 56 70 56 28 8 1

其中第 n n n行第 k k k列代表的数字为 C n k C_n^k Cnk
容易发现帕斯卡三角形的几条性质:

  1. C n k = C n − 1 k − 1 + C n − 1 k C_n^k=C_{n-1}^{k-1}+C_{n-1}^k Cnk=Cn1k1+Cn1k,从表上容易看出
  2. 对称关系 C n k = C n n − k C_n^k=C_n^{n-k} Cnk=Cnnk
  3. 假设从 ( 0 , 0 ) (0,0) (0,0)出发只能向下或向右下走,那么到达 ( n , k ) (n,k) (n,k)的路径数为 C n k C_n^{k} Cnk
  4. C n i , i ∈ [ 0 , n ] C_n^i,i\in[0,n] Cni,i[0,n]具有单峰性,即当 n n n为偶数有 C n 0 < C n 1 < C n 2 < . . . < C n n 2 − 1 < C n n 2 > C n n 2 + 1 > . . . > C n n − 2 > C n n − 1 > C n n C_n^0C_n^{\frac n2+1}>...>C_n^{n-2}>C_n^{n-1}>C_n^{n} Cn0<Cn1<Cn2<...<Cn2n1<Cn2n>Cn2n+1>...>Cnn2>Cnn1>Cnn;当 n n n为奇数有 C n 0 < C n 1 < C n 2 < . . . < C n n − 1 2 = C n n + 1 2 > . . . > C n n − 2 > C n n − 1 > C n n C_n^0...>C_{n}^{n-2}>C_n^{n-1}>C_n^n Cn0<Cn1<Cn2<...<Cn2n1=Cn2n+1>...>Cnn2>Cnn1>Cnn成立。

3.组合数性质

  1. k ( n k ) = n ( n − 1 k − 1 ) k\binom{n}{k}=n\binom{n-1}{k-1} k(kn)=n(k1n1),也常写作 ( n k ) = n k ( n − 1 k − 1 ) \tbinom{n}k=\frac nk\tbinom{n-1}{k-1} (kn)=kn(k1n1)
    证明: k ( n k ) = k n ! k ! ( n − k ) ! = n ( n − 1 ) ! ( k − 1 ) ! ( n − 1 − ( k − 1 ) ) ! = n ( n − 1 k − 1 ) k\binom{n}{k}=k\frac{n!}{k!(n-k)!}=n\frac{(n-1)!}{(k-1)!(n-1-(k-1))!}=n\binom{n-1}{k-1} k(kn)=kk!(nk)!n!=n(k1)!(n1(k1))!(n1)!=n(k1n1)

  2. ( n k ) = ( n n − k ) \binom{n}{k}=\binom{n}{n-k} (kn)=(nkn)
    证明: ( n k ) = n ! k ! ( n − k ) ! = n ! ( n − k ) ! ( n − ( n − k ) ) ! = ( n n − k ) \binom{n}{k}=\frac{n!}{k!(n-k)!}=\frac{n!}{(n-k)!(n-(n-k))!}=\binom{n}{n-k} (kn)=k!(nk)!n!=(nk)!(n(nk))!n!=(nkn)

  3. ∑ i = 0 n ( n i ) = 2 n \sum_{i=0}^n\binom{n}{i}=2^n i=0n(in)=2n
    证明:
    方法一:考虑牛顿二项式有 ( 1 + 1 ) n = ∑ i = 0 n ( n i ) 1 i 1 n − i ⇒ ∑ i = 0 n ( n i ) = 2 n (1+1)^n=\sum_{i=0}^n\binom{n}{i}1^i1^{n-i}\Rightarrow \sum_{i=0}^n\binom{n}{i}=2^n (1+1)n=i=0n(in)1i1nii=0n(in)=2n
    方法二:考虑n个元素的集合的子集个数显然是 2 n 2^n 2n个,从另一个角度来说,我们可以把它的子集按照元素的个数进行划分,对于含有0个元素的子集只有 ( n 0 ) = 1 \tbinom{n}0=1 (0n)=1个,含有1个元素的子集有 ( n 1 ) = n \tbinom{n}1=n (1n)=n个…,因此子集总个数为 ∑ i = 0 ( n i ) = 2 n \sum_{i=0}\binom{n}i=2^n i=0(in)=2n个。

  4. ∑ i = 0 n ( − 1 ) i ( n i ) = 0 \sum_{i=0}^n(-1)^i\binom{n}{i}=0 i=0n(1)i(in)=0
    证明:考虑牛顿二项式 ( 1 − 1 ) n = ∑ i = 0 n ( n i ) ( − 1 ) i 1 n − i ⇒ ∑ i = 0 n ( − 1 ) i ( n i ) = 0 (1-1)^n=\sum_{i=0}^n\binom{n}{i}(-1)^i1^{n-i}\Rightarrow \sum_{i=0}^n(-1)^i\binom{n}{i}=0 (11)n=i=0n(in)(1)i1nii=0n(1)i(in)=0

  5. ( n 0 ) + ( n 2 ) + ( n 4 ) + . . . = ( n 1 ) + ( n 3 ) + ( n 5 ) + . . . = 2 n − 1 \binom{n}{0}+\binom{n}{2}+\binom{n}{4}+...=\binom{n}{1}+\binom{n}{3}+\binom{n}{5}+...=2^{n-1} (0n)+(2n)+(4n)+...=(1n)+(3n)+(5n)+...=2n1
    证明:由4可知 ∑ i = 0 n ( n i ) ( − 1 ) i = 0 \sum_{i=0}^n\binom{n}{i}(-1)^i=0 i=0n(in)(1)i=0,因此有奇数项和与偶数项和相等。

  6. ∑ i = 0 n i ( n i ) = n 2 n − 1 \sum_{i=0}^ni\binom{n}i=n2^{n-1} i=0ni(in)=n2n1
    证明:由于1可知 i ( n i ) = n ( n − 1 i − 1 ) i\binom{n}{i}=n\binom{n-1}{i-1} i(in)=n(i1n1),因此有:
    ∑ i = 0 n i ( n i ) = ∑ i = 1 n i ( n i ) = ∑ i = 1 n n ( n − 1 i − 1 ) = n ∑ i = 0 n − 1 ( n − 1 i ) = n 2 n − 1 \begin{aligned} \sum_{i=0}^ni\tbinom{n}{i}&=\sum_{i=1}^ni\tbinom{n}i\\ &=\sum_{i=1}^nn\tbinom {n-1}{i-1}\\ &=n\sum_{i=0}^{n-1}\tbinom{n-1}i\\ &=n2^{n-1} \end{aligned} i=0ni(in)=i=1ni(in)=i=1nn(i1n1)=ni=0n1(in1)=n2n1

  7. ∑ i = 0 n i 2 ( n i ) = n ( n + 1 ) 2 n − 2 \sum_{i=0}^ni^2\tbinom{n}{i}=n(n+1)2^{n-2} i=0ni2(in)=n(n+1)2n2
    证明:类似于6的证明。
    ∑ i = 0 n i 2 ( n i ) = ∑ i = 1 n i n ( n − 1 i − 1 ) = n ∑ i = 0 n − 1 ( i + 1 ) ( n − 1 i ) = n ( ∑ i = 0 n − 1 i ( n − 1 i ) + ∑ i = 0 n − 1 ( n − 1 i ) ) = n [ ( n − 1 ) 2 n − 2 + 2 n − 1 ] = n ( n + 1 ) 2 n − 2 \begin{aligned} \sum_{i=0}^ni^2\tbinom{n}{i}&=\sum_{i=1}^nin\tbinom{n-1}{i-1}\\ &=n\sum_{i=0}^{n-1}(i+1)\tbinom{n-1}{i}\\ &=n(\sum_{i=0}^{n-1}i\tbinom{n-1}i+\sum_{i=0}^{n-1}\tbinom{n-1}{i})\\ &=n[(n-1)2^{n-2}+2^{n-1}]\\ &=n(n+1)2^{n-2} \end{aligned} i=0ni2(in)=i=1nin(i1n1)=ni=0n1(i+1)(in1)=n(i=0n1i(in1)+i=0n1(in1))=n[(n1)2n2+2n1]=n(n+1)2n2

  8. ∑ i = 0 m ( n i ) ( m m − i ) = ( m + n m ) , m ≤ n \sum_{i=0}^m\tbinom{n}{i}\tbinom{m}{m-i}=\tbinom{m+n}{m},m\le n i=0m(in)(mim)=(mm+n),mn
    证明:考虑 ( m + n m ) \binom{m+n}m (mm+n)的组合学意义,它代表的是从 n n n个元素的集合 A A A中和 m m m个元素的集合 B B B中选出 m m m个元素,显然我们可以按照从集合 A A A中选出的元素个数 i i i来对方案进行划分,集合 A A A中选择 i i i个元素的方案数为 ( n i ) \binom{n}i (in),还需要从集合 B B B中选择 m − i m-i mi个元素,有 ( m m − i ) \binom{m}{m-i} (mim),然后根据乘法原理乘起来即可,然后要对所有的 i , i ∈ [ 0 , m ] i,i\in[0,m] ii[0,m]对应的方案数求和,得到 ∑ i = 0 m ( n i ) ( m m − i ) = ( m + n m ) \sum_{i=0}^m\tbinom{n}{i}\tbinom{m}{m-i}=\tbinom{m+n}{m} i=0m(in)(mim)=(mm+n)

  9. ∑ i = 0 n ( n i ) 2 = ( 2 n n ) \sum_{i=0}^n\tbinom{n}i^2=\tbinom{2n}{n} i=0n(in)2=(n2n)
    证明:根据8我们知道 ( 2 n n ) = ∑ i = 0 n ( n i ) ( n n − i ) = ∑ i = 0 n ( n i ) 2 \tbinom{2n}n=\sum_{i=0}^n\tbinom{n}i\tbinom{n}{n-i}=\sum_{i=0}^n\tbinom{n}{i}^2 (n2n)=i=0n(in)(nin)=i=0n(in)2

  10. ( n k ) = ( n − 1 k − 1 ) + ( n − 1 k ) \tbinom{n}{k}=\tbinom{n-1}{k-1}+\tbinom{n-1}{k} (kn)=(k1n1)+(kn1),当 n < k nn<k的时候该式子也成立。
    证明:考虑 ( n k ) \tbinom{n}k (kn)的组合学意义,我们要从 n n n个元素中取 k k k个元素,假设其中一个元素为 a a a,那么我们可以取的方案有两种,一种是包括 a a a元素的,一种是不包括 a a a元素的。对于第一种方案我们有 ( n − 1 k − 1 ) \tbinom{n-1}{k-1} (k1n1)种取法,对于第二种方案我们有 ( n − 1 k ) \tbinom{n-1}k (kn1)种取法,故有关系式 ( n k ) = ( n − 1 k − 1 ) + ( n − 1 k ) \tbinom{n}{k}=\tbinom{n-1}{k-1}+\tbinom{n-1}{k} (kn)=(k1n1)+(kn1)成立。
    n < k nn<k时有 n − 1 < k − 1 , n − 1 < k n-1n1<k1,n1<k,故有 ( n k ) = ( n − 1 k − 1 ) = ( n − 1 k ) = 0 \tbinom nk=\binom{n-1}{k-1}=\binom{n-1}k=0 (kn)=(k1n1)=(kn1)=0,故公式仍然适用。

  11. ∑ i = 0 n ( i k ) = ( n + 1 k + 1 ) \sum_{i=0}^n\tbinom{i}{k}=\tbinom{n+1}{k+1} i=0n(ki)=(k+1n+1) ,在该式子中 n n n k k k的大小关系可以任意。
    证明:利用10的关系式递推即可:
    ( 0 k ) + ( 0 k + 1 ) = ( 1 k + 1 ) \binom{0}k+\binom 0{k+1}=\binom 1{k+1} (k0)+(k+10)=(k+11)
    ( 1 k + 1 ) + ( 1 k ) = ( 2 k + 1 ) \binom 1{k+1}+\binom 1k=\binom 2{k+1} (k+11)+(k1)=(k+12)
    ( 2 k + 1 ) + ( 2 k ) = ( 3 k + 1 ) \binom 2{k+1}+\binom 2k=\binom 3{k+1} (k+12)+(k2)=(k+13)

    ( n k + 1 ) + ( n k ) = ( n + 1 k + 1 ) \binom n{k+1}+\binom nk=\binom {n+1}{k+1} (k+1n)+(kn)=(k+1n+1)
    将左边项加起来,右边项也加起来就得到 ( 0 k + 1 ) + ∑ i = 0 n ( i k ) = ( n + 1 k + 1 ) \tbinom 0{k+1}+\sum_{i=0}^n\tbinom{i}k=\tbinom{n+1}{k+1} (k+10)+i=0n(ki)=(k+1n+1),由于 k ≥ 0 k\ge 0 k0,故 ( 0 k + 1 ) = 0 \tbinom{0}{k+1}=0 (k+10)=0,因此有 ∑ i = 0 n ( i k ) = ( n + 1 k + 1 ) \sum_{i=0}^n\tbinom{i}k=\tbinom{n+1}{k+1} i=0n(ki)=(k+1n+1)
    又因为我们递推过程中用到的性质(即性质10)没有对 n n n k k k之间的大小关系由限制,故式子在 n n n k k k任意大小关系的情况下都成立。

  12. ( n i ) ( i k ) = ( n k ) ( n − k i − k ) = ( n k ) ( n − k n − i ) \tbinom{n}i\tbinom ik=\tbinom nk\tbinom {n-k}{i-k}=\tbinom{n}{k}\tbinom{n-k}{n-i} (in)(ki)=(kn)(iknk)=(kn)(nink),其中 n , i , k n,i,k n,i,k的大小关系任意。
    证明: ( n i ) ( i k ) = n ! i ! ( n − i ) ! i ! k ! ( i − k ) ! = n ! k ! 1 ( i − k ) ! ( n − i ) ! = n ! k ! ( n − k ) ! ( n − k ) ! ( i − k ) ! [ ( n − k ) − ( i − k ) ] ! = ( n k ) ( n − k i − k ) \tbinom{n}i\tbinom ik=\frac {n!}{i!(n-i)!}\frac {i!}{k!(i-k)!}=\frac{n!}{k!}\frac 1{(i-k)!(n-i)!}=\frac {n!}{k!(n-k)!}\frac {(n-k)!}{(i-k)![(n-k)-(i-k)]!}=\tbinom{n}k\tbinom{n-k}{i-k} (in)(ki)=i!(ni)!n!k!(ik)!i!=k!n!(ik)!(ni)!1=k!(nk)!n!(ik)![(nk)(ik)]!(nk)!=(kn)(iknk)。对于 i > n i>n i>n k > i k>i k>i的情况容易验证也是正确的。

  13. ∑ i = 0 n ( n − i i ) = F n + 1 \sum_{i=0}^n\tbinom{n-i}i=F_{n+1} i=0n(ini)=Fn+1 F n F_n Fn为斐波拉契数列,事实上这个式子代表的是杨辉三角斜对角线之和等于斐波拉契数列,如下图所示。
    杨辉三角
    证明:由图中可以直接得证,我们考虑三个连续的相邻的对角线上的数字的关系,第一个对角线与第二个对角线上相同行的两个数字相加均可以得到第三个对角线上的数字,如下图所示(取任意三个连续对角线,红框表示一个对角线和第二个对角线上的数字,蓝框表示第三个对角线上的数字,紫框中的数相加后得到蓝色框的对应的数字):acm-排列组合学习笔记(更新中)_第1张图片
    当然也可以直接由公式推导证明,只是没有这么直观,我们有:
    ∑ i = 0 n ( n − i i ) + ∑ i = 0 n + 1 ( n + 1 − i i ) = ∑ i = 1 n + 1 ( n + 1 − i i − 1 ) + ∑ i = 0 n + 1 ( n + 1 − i i ) = ∑ i = 1 n + 1 ( ( n + 1 − i i − 1 ) + ( n + 1 − i i ) ) + 1 = ∑ i = 1 n + 1 ( n + 2 − i i ) + ( n + 2 0 ) = ∑ i = 0 n + 1 ( n + 2 − i i ) + 0 = ∑ i = 0 n + 1 ( n + 2 − i i ) + ( 0 n + 2 ) = ∑ i = 0 n + 2 ( n + 2 − i i ) \begin{aligned} \sum_{i=0}^n\tbinom{n-i}{i}+\sum_{i=0}^{n+1}\tbinom{n+1-i}i&=\sum_{i=1}^{n+1}\tbinom{n+1-i}{i-1}+\sum_{i=0}^{n+1}\tbinom{n+1-i}{i}\\ &=\sum_{i=1}^{n+1}(\tbinom{n+1-i}{i-1}+\tbinom{n+1-i}{i})+1\\ &=\sum_{i=1}^{n+1}\tbinom{n+2-i}{i}+\tbinom{n+2}{0}\\ &=\sum_{i=0}^{n+1}\tbinom{n+2-i}i+0\\ &=\sum_{i=0}^{n+1}\tbinom{n+2-i}i+\tbinom{0}{n+2}\\ &=\sum_{i=0}^{n+2}\tbinom{n+2-i}i\\ \end{aligned} i=0n(ini)+i=0n+1(in+1i)=i=1n+1(i1n+1i)+i=0n+1(in+1i)=i=1n+1((i1n+1i)+(in+1i))+1=i=1n+1(in+2i)+(0n+2)=i=0n+1(in+2i)+0=i=0n+1(in+2i)+(n+20)=i=0n+2(in+2i)
    显然满足斐波拉契定义,并且由图可直接验证公式在 n = 0 , 1 , 2 n=0,1,2 n=0,1,2的时候都成立,因此公式成立。

4.组合数取模及求解

组合数取模的话有四种方法,分别适用于不同的情况。

(1).Pascal打表法(批量)

根据二.3.10我们有公式 ( n k ) = ( n − 1 k − 1 ) + ( n − 1 k ) \binom{n}{k}=\binom{n-1}{k-1}+\binom{n-1}{k} (kn)=(k1n1)+(kn1)成立,故我们考虑利用这个公式递推即可,也就是打表,边界条件为 ( 0 0 ) = 1 \binom 00=1 (00)=1
时间复杂度: O ( n 2 ) O(n^2) O(n2)预处理, O ( 1 ) O(1) O(1)查询。
空间复杂度: O ( n 2 ) O(n^2) O(n2)
一般适用范围: n , k ≤ 5000 n,k\le 5000 n,k5000
这里给出一份参考代码。

const int mod = 1e9+7;
int c[maxn][maxn];
void init(int n){
	c[0][0]=1;
	FOR(i,1,n+1){
		c[i][0]=1;
		FOR(j,1,n+1)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
	}
}

(2).公式法(单个)

利用组合数的定义式 C n k = n ! k ! ( n − k ) ! C_n^k=\frac{n!}{k!(n-k)!} Cnk=k!(nk)!n!进行求解,不过这里有三种不同的方式对公式进行求解。

[1].方法一

考虑预处理出 1 1 1~ n n n的所有数的阶乘以及阶乘的逆元,于是可以直接代入式子计算。关于阶乘逆元的求解原理详见基础数论学习笔记(上)第五部分1.(3).[4].情况二
时间复杂度: O ( n ) O(n) O(n)预处理, O ( 1 ) O(1) O(1)查询
空间复杂度: O ( n ) O(n) O(n)
一般适用范围: n , k ≤ 1 e 8 n,k\le 1e8 n,k1e8
这里给出一份参考代码。

const int mod = 1e9+7;
int fac[maxn],fav[maxn];//fac[n]=n!,fav[n]=inv(fac[n]) 
void init(int n){//预处理阶乘和它的逆元
	fac[0]=1;
	FOR(i,1,n+1)fac[i]=1ll*fac[i-1]*i%mod;
	fav[n]=qpow(fac[n],mod-2,mod);
	ROF(i,n-1,0)fav[i]=1ll*(i+1)*fav[i+1]%mod;
}
int C(int n,int k){
	if(n<k)return 0;
	return 1ll*fac[n]*fav[k]%mod*fav[n-k]%mod;
}
[2].方法二

仍然考虑预处理出 1 1 1~ n n n的阶乘的逆元,然后由于的 C n k = n ! k ! ( n − k ) ! = n ( n − 1 ) ( n − 2 ) . . . ( n − k + 1 ) k ! C_n^k=\frac {n!}{k!(n-k)!}=\frac{n(n-1)(n-2)...(n-k+1)}{k!} Cnk=k!(nk)!n!=k!n(n1)(n2)...(nk+1),注意到分子和分母其实都只有 k k k项,因此在 n n n很大但是 k k k很小的时候可以暴力处理,其中分母可以预处理它的逆元,分子可以暴力 O ( k ) O(k) O(k)计算。
时间复杂度: O ( n ) O(n) O(n)预处理, O ( k ) O(k) O(k)查询
空间复杂度: O ( n ) O(n) O(n)
一般适用范围: n ≤ 1 e 18 n\le 1e18 n1e18, k ≤ 1 e 8 k\le 1e8 k1e8
这里给出一份参考代码。

const int mod = 1e9+7;
int fac[maxn],fav[maxn];//fac[n]=n!,fav[n]=inv(fac[n]) 
void init(int n){
	fac[0]=1;
	FOR(i,1,n+1)fac[i]=1ll*fac[i-1]*i%mod;
	fav[n]=qpow(fac[n],mod-2,mod);
	ROF(i,n-1,0)fav[i]=1ll*(i+1)*fav[i+1]%mod;
}

int C(ll n,int k){
	if(n<k)return 0;
	int ans=1;
	FOR(i,0,k)ans=1ll*ans*(((n-i))%mod)%mod;
	return 1ll*ans*fav[k]%mod;
}
[3].方法三

当模数不为质数的时候前两个方法都将无法使用,因为我们无法求出阶乘的逆元,这时候我们可以考虑计算质数因子对组合数的贡献。具体地,我们设 c n t [ i ] cnt[i] cnt[i]表示对答案的贡献,令 m i n p [ i ] minp[i] minp[i]表示 i i i的最小质因子,由于 ( n k ) = ∏ i = n − k + 1 n i ∏ i = 1 k i \tbinom{n}k=\frac{\prod_{i=n-k+1}^ni}{\prod_{i=1}^ki} (kn)=i=1kii=nk+1ni,因此我们初始化 c n t [ n − k + 1 ∼ n ] cnt[n-k+1\sim n] cnt[nk+1n] 1 1 1以及 c n t [ 1 ∼ k ] cnt[1\sim k] cnt[1k] − 1 -1 1,重合部分设成 0 0 0。然后考虑把每个合数 c n t cnt cnt的贡献分解为质数 c n t cnt cnt的贡献。转移方程也很容易写出来,显然有 c n t [ m i n p [ i ] ] + = c n t [ i ] , c n t [ i m i n p [ i ] ] + = c n t [ i ] cnt[minp[i]]+=cnt[i],cnt[\frac i{minp[i]}]+=cnt[i] cnt[minp[i]]+=cnt[i],cnt[minp[i]i]+=cnt[i],如果从大到小对每个合数进行转移的话就能够把合数的贡献分解为每个质数的贡献,最后我们把所有质数的贡献全部乘起来即可。注意这些贡献指的是幂次,故需要用到快速幂,转移复杂度是 O ( n ) O(n) O(n)的,但是由于用到快速幂的缘故会导致复杂度变成 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

时间复杂度: O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

空间复杂度: O ( n ) O(n) O(n)

一般适用范围:模数为合数, n , k ≤ 1 e 6 n,k\le 1e6 n,k1e6,单值查询

这里给出一份参考代码。

int prim[maxn],tot,minp[maxn],cnt[maxn];
void init(int n){
	FOR(i,2,n+1){
		if(!minp[i])prim[tot++]=i;
		for(register int j =0;j<tot && prim[j]*i<=n;++j){
			minp[i*prim[j]]=prim[j];
			if(i%prim[j]==0)break;
		}
	} 
}
int C(int n,int k,int mod){
	if(k>n-k)k=n-k;
	FOR(i,1,k+1)cnt[i]--;
	ROF(i,n,n-k+1)cnt[i]++;
	ROF(i,n,2){
		if(minp[i]){
			cnt[minp[i]]+=cnt[i];
			cnt[i/minp[i]]+=cnt[i];
		}
	}
	register int ans=1;
	FOR(i,2,n+1)if(cnt[i] && !minp[i])ans=1ll*ans*qpow(i,cnt[i],mod)%mod;
	return ans;
}
int main(){
	init(1000);
	wrn(C(5,3,7));
} 

(3).卢卡斯定理

卢卡斯定理在基础数论学习笔记(上)第四部分8.(1)有详细的讲解,这里再给出简单的介绍。
首先是三个前置引理(下文中的 p p p均是质数):

  1. 组合数是整数。
    证明:根据组合数的意义显然正确。

  2. p ∣ ( p i ) , i ∈ [ 1 , p − 1 ] p\mid \tbinom{p}{i},i\in[1,p-1] p(ip),i[1,p1]
    证明: ( p i ) = p ( p − 1 ) . . . ( p − i + 1 ) i ! \tbinom pi=\frac{p(p-1)...(p-i+1)}{i!} (ip)=i!p(p1)...(pi+1),由于组合数是整数且 g c d ( i ! , p ) = 1 gcd(i!,p)=1 gcd(i!,p)=1,因此有 i ! ∣ ( p − 1 ) ( p − 2 ) . . . ( p − i + 1 ) i!\mid (p-1)(p-2)...(p-i+1) i!(p1)(p2)...(pi+1),故 p ∣ ( p i ) , i ∈ [ 1 , p − 1 ] p\mid \tbinom{p}{i},i\in[1,p-1] p(ip),i[1,p1]

  3. ( 1 + x ) p ≡ 1 + x p ( m o d p ) (1+x)^{p}\equiv 1+x^p\pmod p (1+x)p1+xp(modp)
    证明:考虑二项式定理和引理2有 ( 1 + x ) p ≡ ( p 0 ) x 0 + ( p 1 ) x 1 + ( p 2 ) x 2 + . . . + ( p p − 1 ) x p − 1 + ( p p ) x p ≡ 1 + x p ( m o d p ) (1+x)^p\equiv \tbinom{p}{0}x^0+\tbinom{p}{1}x^1+\tbinom{p}{2}x^2+...+\tbinom{p}{p-1}x^{p-1}+\tbinom{p}{p}x^{p}\equiv 1+x^p\pmod p (1+x)p(0p)x0+(1p)x1+(2p)x2+...+(p1p)xp1+(pp)xp1+xp(modp)

首先设组合数 ( a b ) , a ≥ b \tbinom{a}{b},a\ge b (ba),ab,我们对 a a a b b b写成 p p p进制的形式有 a = a 0 p 0 + a 1 p 1 + . . . + a k p k , b = b 0 p 0 + b 1 p 1 + . . . b k p k a=a_0p^0+a_1p^1+...+a_kp^k,b=b_0p^0+b_1p^1+...b_kp^k a=a0p0+a1p1+...+akpk,b=b0p0+b1p1+...bkpk
于是 ( 1 + x ) a % p (1+x)^a\% p (1+x)a%p可以写成 ( 1 + x ) a 0 p 0 ( 1 + x ) a 1 p 1 . . . ( 1 + x ) a k p k ≡ ( 1 + x p 0 ) a 0 ( 1 + x p 1 ) a 1 . . . ( 1 + x p k ) a k ( m o d p ) (1+x)^{a_0p^0}(1+x)^{a_1p^1}...(1+x)^{a_kp^k}\equiv (1+x^{p^0})^{a_0}(1+x^{p^1})^{a_1}...(1+x^{p^k})^{a_k}\pmod p (1+x)a0p0(1+x)a1p1...(1+x)akpk(1+xp0)a0(1+xp1)a1...(1+xpk)ak(modp)(这里套了引理3的变换),然后考虑 ( 1 + x ) a (1+x)^a (1+x)a的第 b b b项的系数显然为 ( a b ) \tbinom{a}{b} (ba),除此之外根据它还可以表示为从 ( 1 + x p 0 ) a 0 (1+x^{p^0})^{a_0} (1+xp0)a0中选择 x b 0 p 0 x^{b_0p_0} xb0p0项,从 ( 1 + x p 1 ) a 1 (1+x^{p^1})^{a_1} (1+xp1)a1中选择 x b 1 p 1 x^{b_1p_1} xb1p1…它们选择的方案数分别是 ( a 0 b 0 ) , ( a 1 b 1 ) , . . . , ( a k b k ) \tbinom{a_0}{b_0},\tbinom{a_1}{b_1},...,\tbinom{a_k}{b_k} (b0a0),(b1a1),...,(bkak),于是能够得到 ( a b ) = ( a 0 b 0 ) ( a 1 b 1 ) ⋯ ( a k b k ) \tbinom{a}{b}=\tbinom{a_0}{b_0}\tbinom{a_1}{b_1}\cdots\tbinom{a_k}{b_k} (ba)=(b0a0)(b1a1)(bkak),这也是卢卡斯定理的一种表述形式,不过更常写成它的递推形式 ( a b ) = ( ⌊ a p ⌋ ⌊ b p ⌋ ) ( a % p b % p ) \tbinom{a}b=\tbinom{\lfloor \frac ap\rfloor}{\lfloor \frac bp\rfloor}\tbinom{a\%p}{b\%p} (ba)=(pbpa)(b%pa%p)

上述证明可能有个令人困惑的地方,即当 a i < b i a_iai<bi的时候如何从 ( 1 + x p i ) a i (1+x^{p^i})^{a_i} (1+xpi)ai中选出 x b i p i x^{b_ip_i} xbipi,确实,没办法选出来,根据进制特性由于我们只能从 ( 1 + x p i ) a i (1+x^{p^i})^{a_i} (1+xpi)ai中组合出 x b i p i x^{b_ip_i} xbipi,无法从其它地方拼凑出 x b i p i x^{b_ip_i} xbipi,故我们可以认为 x b i p i x^{b_ip^i} xbipi这一项不存在,进一步也就是 x b x^b xb不存在。但 ( 1 + x ) a (1+x)^a (1+x)a显然可以拼凑出 x b x^b xb这一项,为什么说它不存在呢?这里不存在的意思是指它的系数为0,系数为0是因为在应用引理3的时候把它的系数给模掉了,故它的系数为0,不过这与组合数的定义是契合的,因为此时有 ( a i b i ) = 0 , i f    b i > a i \tbinom{a_i}{b_i}=0,if\;b_i>a_i (biai)=0,ifbi>ai,从而有 ( a b ) ≡ 0 ( m o d p ) \tbinom{a}{b}\equiv 0\pmod p (ba)0(modp)

然后关于卢卡斯定理有个重要的推论,关于证明这里不详述,已经在上面的链接中给出。
其内容主要是: ( n m ) \tbinom{n}{m} (mn)为奇数,则 n & m = m n\&m=m n&m=m

时间复杂度: O ( p ) O(p) O(p)预处理, O ( l o g p n ) O(log_pn) O(logpn)查询
空间复杂度: O ( p ) O(p) O(p)
适用范围: n ≤ 1 e 18 , p ≤ 1 e 8 n\le 1e18,p\le 1e8 n1e18,p1e8,其中 p p p必须是质数

这里以LuoGu的P3807 【模板】卢卡斯定理为例给出一份参考代码:

int mod,fac[maxn],fav[maxn];
inline int C(int n,int m){
	if(n<m)return 0;
	return 1ll*fac[n]*fav[m]%mod*fav[n-m]%mod;
}
inline int lucas(int n,int m){
	if(n<m)return 0;
	if(!m)return 1;
	register int cc=C(n%mod,m%mod);
	if(!cc)return 0;
	return 1ll*cc*lucas(n/mod,m/mod)%mod;
}
int main(){
	int t;
	rd(&t);
	while(t--){
		register int n,m,p;
		rd(&n,&m,&p);
		n+=m;
		mod=p;
		fac[0]=1;
		FOR(i,1,p)fac[i]=1ll*fac[i-1]*i%mod;
		fav[p-1]=qpow(fac[p-1],mod-2,mod);
		ROF(i,p-2,0)fav[i]=1ll*fav[i+1]*(i+1)%mod;
		wrn(lucas(n,m));
	}
}

(4).扩展卢卡斯

扩展卢卡斯在基础数论学习笔记(上)第四部分8.(2)有详细的讲解,这里不过多介绍(太懒了不想写 )
其主要目的是解决 p p p为合数的情况,一般 p p p范围比较小又是合数,而 n , m n,m n,m范围很大则需要用到扩展卢卡斯。

这里以LuoGu的P4720 【模板】扩展卢卡斯为例给出一份参考代码。

int a[50],mod[50],cnt; 
inline int getfac(ll n,int p,int pk,int fg){
	if(!n)return 1;
	register int res=1,ans=1;
	FOR(i,1,pk+1)if(i%p)res=1ll*res*i%pk;
	cnt+=fg*(n/p);
	ans=qpow(res,n/pk,pk);
	res=n%pk;
	FOR(i,1,res+1)if(i%p)ans=1ll*ans*i%pk;
	return 1ll*ans*getfac(n/p,p,pk,fg)%pk;
}
void exgcd(int a,int b,int &x,int &y){
	if(!b)x=1,y=0;
	else exgcd(b,a%b,y,x),y-=a/b*x;
}
int inv(int a,int p){
	a%=p;
	int x,y;
	exgcd(a,p,x,y);
	return (x%p+p)%p;
}
inline int C(ll n,ll m,int p,int pk){
	if(n<m)return 0;
	if(!m)return 1;
	cnt=0;
	int a=getfac(n,p,pk,1),b=getfac(m,p,pk,-1),c=getfac(n-m,p,pk,-1);
	return 1ll*a*inv(b,pk)%pk*inv(c,pk)%pk*qpow(p,cnt,pk)%pk;
}
int crt(int *a,int *m,int n){
	int M=1,ans=0;
	FOR(i,0,n)M*=m[i];
	FOR(i,0,n){
		register int Mi=M/m[i],ti=inv(Mi,m[i]);
		ans=(ans+1ll*a[i]*Mi%M*ti%M)%M;
	}
	return ans;
}
int exlucas(ll n,ll m,int p){
	register int tot=0;
	for(register int i=2;i*i<=p;++i){
		if(p%i==0){
			register int pk=1;
			while(p%i==0){
				pk*=i;
				p/=i;
			}
			a[tot++]=C(n,m,i,pk);
			mod[tot-1]=pk;
		}
	}
	if(p>1)a[tot++]=C(n,m,p,p),mod[tot-1]=p;
	return crt(a,mod,tot);
}
int main(){
	ll n,m;int p;
	rd(&n,&m,&p);
	wrn(exlucas(n,m,p));
}

三、特殊排列组合

1.不相邻组合

从集合 { 1 , 2 , 3 , . . . , n } \{1,2,3,...,n\} {1,2,3,...,n}中选择 k k k个数,满足这 k k k个数两两均不相邻的组合方式有 ( n − k + 1 k ) \tbinom{n-k+1}{k} (knk+1)种。

证明:设从 { 1 , 2 , 3 , . . . , n } \{1,2,3,...,n\} {1,2,3,...,n}中选择 k k k个不相邻数为 a 1 < a 2 < , . . . , < a k , a i − a i − 1 ≥ 2 , ∀ i ∈ [ 2 , k ] a_1a1<a2<,...,<ak,aiai12,i[2,k],设从 { 1 , 2 , 3 , . . . , n − k + 1 } \{1,2,3,...,n-k+1\} {1,2,3,...,nk+1}中选择 k k k个不同的数为 b 1 , b 2 , . . . , b k , b i − b i − 1 ≥ 1 , ∀ i ∈ [ 2 , k ] b_1,b_2,...,b_k,b_i-b_{i-1}\ge 1,\forall i\in[2,k] b1,b2,...,bk,bibi11,i[2,k],我们只需要说明 { a i } \{a_i\} {ai} { b i } \{b_i\} {bi<

你可能感兴趣的:(组合计数,acm竞赛,算法)