acm模板-组合数学

发布于 2021-10-21  2406 次阅读


组合数学

卢卡斯定理

(nm)modp=(n/pm/p)(nmodpmmodp)modp

LL Lucas(LL n, LL m, LL mod) {
if (m == 0) return 1;
return (C(n % mod, m % mod, mod) * Lucas(n / mod, m / mod, mod)) % mod;
}

拓展卢卡斯定理

LL calc(LL n, LL x, LL mod) {
if (!n) return 1;
LL s = 1;
for (LL i = 1; i <= mod; i++)
if (i % x) s = s * i % mod;
s = ksm(s, n / mod, mod);
for (LL i = n / mod * mod + 1; i <= n; i++)
if (i % x) s = i % mod * s % mod;
return s * calc(n / x, x, mod) % mod;
}
LL multilucas(LL m, LL n, LL x, LL mod) {
int cnt = 0;
for (LL i = m; i; i /= x) cnt += i / x;
for (LL i = n; i; i /= x) cnt -= i / x;
for (LL i = m - n; i; i /= x) cnt -= i / x;
return ksm(x, cnt, mod) % mod * calc(m, x, mod) % mod *
ksm(calc(n, x, mod), mod - 2, mod) % mod *
ksm(calc(m - n, x, mod), mod - 2, mod) % mod;
}
LL exlucas(LL m, LL n, LL mod) {
int cnt = 0;
LL p[20], a[20];
for (LL i = 2; i * i <= mod; i++)
if (mod % i == 0) {
p[++cnt] = 1;
while (mod % i == 0) p[cnt] = p[cnt] * i, mod /= i;
a[cnt] = multilucas(m, n, i, p[cnt]);
}
if (mod > 1) p[++cnt] = mod, a[cnt] = multilucas(m, n, mod, mod);
return CRT(cnt, a, p);
}

二项式定理

(a+b)n=i=0n(ni)anibi

(nn1n2nt)=tn

模型

多重集的组合数 1

S=n1a1,n2a2,,nkak, 表示由 n1a1n2a2,…,nkak 组成的多重集。那么对于整数 r(r<ni,i[1,k]),从 S 中选择 r 个元素组成一个多重集的方案数就是 多重集的组合数。这个问题等价于 x1+x2++xk=r 的非负整数解的数目,可以用插板法解决,答案为

(r+k1k1)

多重集的组合数 2

考虑这个问题:设 S=n1a1,n2a2,,nkak, 表示由 n1a1n2a2,…,nkak 组成的多重集。那么对于正整数 r,从 S 中选择 r 个元素组成一个多重集的方案数。

这样就限制了每种元素的取的个数。同样的,我们可以把这个问题转化为带限制的线性方程求解:

$$ \forall i\in [1,k],\ x_i\le ni,\ \sum{i=1}^kx_i=r $$

$$ Ans=\sum{p=0}^k(-1)^p\sum{A}\binom{k+r-1-\sum{A} n{A_i}-p}{k-1} $$

其中 A 是充当枚举子集的作用,满足 $ |A|=p,\ Ai<A{i+1} $。

不相邻的排列

1nn 个自然数中选 k 个,这 k 个数中任何两个数都不相邻的组合有 (nk+1k) 种。

错位排列

我们把错位排列问题具体化,考虑这样一个问题:

n 封不同的信,编号分别是 1,2,3,4,5,现在要把这五封信放在编号 1,2,3,4,5 的信封中,要求信封的编号与信的编号不一样。问有多少种不同的放置方法?

错位排列的递推式为 f(n)=(n1)(f(n1)+f(n2))

圆排列

n 个人全部来围成一圈,所有的排列数记为 Qnn。考虑其中已经排好的一圈,从不同位置断开,又变成不同的队列。 所以有

Qnn×n=AnnQn=Annn=(n1)!

由此可知部分圆排列的公式:

Qnr=Anrr=n!r×(nr)!

组合数性质 | 二项式推论

由于组合数在 OI 中十分重要,因此在此介绍一些组合数的性质。

(1)(nm)=(nnm)

相当于将选出的集合对全集取补集,故数值不变。(对称性)

(2)(nk)=nk(n1k1)

由定义导出的递推式。

(3)(nm)=(n1m)+(n1m1)

组合数的递推式(杨辉三角的公式表达)。我们可以利用这个式子,在 O(n2) 的复杂度下推导组合数。

(4)(n0)+(n1)++(nn)=i=0n(ni)=2n

这是二项式定理的特殊情况。取 a=b=1 就得到上式。

(5)i=0n(1)i(ni)=[n=0]

二项式定理的另一种特殊情况,可取 a=1,b=1。式子的特殊情况是取 n=0 时答案为 1

(6)i=0m(ni)(mmi)=(m+nm)   (nm)

拆组合数的式子,在处理某些数据结构题时会用到。

(7)i=0n(ni)2=(2nn)

这是 (6) 的特殊情况,取 n=m 即可。

(8)i=0ni(ni)=n2n1

带权和的一个式子,通过对 (3) 对应的多项式函数求导可以得证。

(9)i=0ni2(ni)=n(n+1)2n2

与上式类似,可以通过对多项式函数求导证明。

(10)l=0n(lk)=(n+1k+1)

可以通过组合意义证明,在恒等式证明中较常用。

(11)(nr)(rk)=(nk)(nkrk)

通过定义可以证明。

$$ \sum{i=0}^n\binom{n-i}{i}=F{n+1}\tag{12} $$

其中 F 是斐波那契数列。

(13)l=0n(lk)=(n+1k+1)

通过组合分析——考虑 $S={a_1, a2, \cdots, a{n+1}}k+1$ 子集数可以得证。

卡特兰数

$$ Hn = \frac{\binom{2n}{n}}{n+1}(n \geq 2, n \in \mathbf{N{+}}) $$

$$ Hn = \begin{cases} \sum{i=1}^{n} H{i-1} H{n-i} & n \geq 2, n \in \mathbf{N_{+}}\ 1 & n = 0, 1 \end{cases} $$

$$ Hn = \frac{H{n-1} (4n-2)}{n+1} $$

Hn=(2nn)(2nn1)

路径计数问题

非降路径是指只能向上或向右走的路径。

  1. (0,0)(m,n) 的非降路径数等于 mxny 的排列数,即 (n+mm)
  2. (0,0)(n,n) 的除端点外不接触直线 y=x 的非降路径数:

先考虑 y=x 下方的路径,都是从 (0,0) 出发,经过 (1,0)(n,n1)(n,n),可以看做是 (1,0)(n,n1) 不接触 y=x 的非降路径数。

所有的的非降路径有 (2n2n1) 条。对于这里面任意一条接触了 y=x 的路径,可以把它最后离开这条线的点到 (1,0) 之间的部分关于 y=x 对称变换,就得到从 (0,1)(n,n1) 的一条非降路径。反之也成立。从而 y=x 下方的非降路径数是 (2n2n1)(2n2n)。根据对称性可知所求答案为 2(2n2n1)2(2n2n)

  1. (0,0)(n,n) 的除端点外不穿过直线 y=x 的非降路径数:

用类似的方法可以得到:2n+1(2nn)

第二类斯特林数(Stirling Number)

第二类斯特林数(斯特林子集数){n k},也可记做 S(n,k),表示将 n 个两两不同的元素,划分为 k 个互不区分的非空子集的方案数。

{n k}={n1 k1}+k{n1 k}

边界是 {n 0}=[n=0]

通项公式

{n m}=i=0m(1)miini!(mi)!

性质:

n^k=∑{ S(k,i) × i! × C(n,i) } i∈[0,k]

n^m = ∑ S(m,k) *[ n! / (n-k)! ] k∈[0,m]

S(m,k) = (1/k!)*∑[ (−1)^(k−i) * C(k,i) * i^m ] i∈[0,k]

第一类斯特林数(Stirling Number)

第一类斯特林数(斯特林轮换数)[n k],也可记做 s(n,k),表示将 n 个两两不同的元素,划分为 k 个互不区分的非空轮换的方案数。

一个轮换就是一个首尾相接的环形排列。我们可以写出一个轮换 [A,B,C,D],并且我们认为 [A,B,C,D]=[B,C,D,A]=[C,D,A,B]=[D,A,B,C],即,两个可以通过旋转而互相得到的轮换是等价的。注意,我们不认为两个可以通过翻转而相互得到的轮换等价,即 [A,B,C,D][D,C,B,A]

递推式[n k]=[n1 k1]+(n1)[n1 k]

边界是 [n 0]=[n=0]

贝尔数

B0=1,B1=1,B2=2,B3=5,B4=15,B5=52,B6=203,

Bn 是基数为 n 的集合的划分方法的数目。集合 S 的一个划分是定义为 S 的两两不相交的非空子集的族,它们的并是 S。例如 B3=5 因为 3 个元素的集合 a,b,c 有 5 种不同的划分方法:

递推公式:

$$ B{n+1}=\sum{k=0}^n\binom{n}{k}B_{k} $$

欧拉数

在计算组合中,欧拉数(Eulerian Number)是从 1n 中正好满足 m 个元素大于前一个元素(具有 m 个“上升”的排列)条件的排列 个数。

int eulerianNumber(int n, int m) {
if (m >= n || n == 0) return 0;
if (m == 0) return 1;
return (((n - m) * eulerianNumber(n - 1, m - 1)) +
((m + 1) * eulerianNumber(n - 1, m)));
}

等幂求和

i=1ni1=n(n+1)2=12n2+12n

i=1ni2=n(n+1)(2n+1)6=13n3+12n2+16n

i=1ni3=[n(n+1)2]2=14n4+12n3+14n2

i=1ni4=n(n+1)(2n+1)(3n2+3n1)30=15n5+12n4+13n3130n

i=1ni5=n2(n+1)2(2n2+2n1)12=16n6+12n5+512n4112n2

预处理逆元 预处理组合数

$\sum{i=0}^n i^k = \frac{1}{k+1} \sum{i=0}^k \binom{k+1}{i} B_{k+1-i} (n+1)^i$.

也可以 $\sum{i=0}^n i^k = \frac{1}{k+1} \sum{i=0}^k \binom{k+1}{i} B^+_{k+1-i} n^iB^+_1 =1/2$。

const int M = 100;
LL inv[M] = {-1, 1};
void inv_init(LL n, LL p) {
for (int i = 2; i < n; ++i) inv[i] = (p - p / i) * inv[p % i] % p;
}
LL C[M][M];
void init_C(int n) {
for (int i = 0; i < n; ++i) {
C[i][0] = C[i][i] = 1;
for (int j = 1; j < i; ++j) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
}
}
LL B[M] = {1};
void init() {
inv_init(M, MOD);
init_C(M);
for (int i = 1; i < M - 1; ++i) {
LL &s = B[i] = 0;
for (int j = 1; j < i; ++j) s += C[i + 1][j] * B[j] % MOD;
s = (s % MOD * -inv[i + 1] % MOD + MOD) % MOD;
}
}
LL p[M] = {1};
LL go(LL n, LL k) {
n %= MOD;
if (k == 0) return n;
for (int i = 1; i < k + 2; ++i) p[i] = p[i - 1] * (n + 1) % MOD;
LL ret = 0;
for (int i = 1; i < k + 2; ++i)
ret += C[k + 1][i] * B[k + 1 - i] % MOD * p[i] % MOD;
ret = ret % MOD * inv[k + 1] % MOD;
return ret;
}

递推公式:

$$ \begin{aligned} S_m{(n)}&=\frac{1}{m+1}(B_0n^{m+1}+\binom{m+1}{1}B_1 n^m+\dots+\binom{m+1}{m}Bm n) \ &=\frac{1}{m+1}\sum{k=0}^{m}\binom{m+1}{k}B_kn^{m+1-k} \end{aligned} $$

Hello, world!
最后更新于 2021-10-21