组合数学
卢卡斯定理
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); }
二项式定理
模型
多重集的组合数 1
设
多重集的组合数 2
考虑这个问题:设
这样就限制了每种元素的取的个数。同样的,我们可以把这个问题转化为带限制的线性方程求解:
$$ \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} $。
不相邻的排列
错位排列
我们把错位排列问题具体化,考虑这样一个问题:
错位排列的递推式为
圆排列
由此可知部分圆排列的公式:
组合数性质 | 二项式推论
由于组合数在 OI 中十分重要,因此在此介绍一些组合数的性质。
相当于将选出的集合对全集取补集,故数值不变。(对称性)
由定义导出的递推式。
组合数的递推式(杨辉三角的公式表达)。我们可以利用这个式子,在
这是二项式定理的特殊情况。取
二项式定理的另一种特殊情况,可取
拆组合数的式子,在处理某些数据结构题时会用到。
这是
带权和的一个式子,通过对
与上式类似,可以通过对多项式函数求导证明。
可以通过组合意义证明,在恒等式证明中较常用。
通过定义可以证明。
$$ \sum{i=0}^n\binom{n-i}{i}=F{n+1}\tag{12} $$
其中
通过组合分析——考虑 $S={a_1, a2, \cdots, a{n+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} $$
路径计数问题
非降路径是指只能向上或向右走的路径。
- 从
到 的非降路径数等于 个 和 个 的排列数,即 。 - 从
到 的除端点外不接触直线 的非降路径数:
先考虑
所有的的非降路径有
- 从
到 的除端点外不穿过直线 的非降路径数:
用类似的方法可以得到:
第二类斯特林数(Stirling Number)
第二类斯特林数(斯特林子集数)
边界是
通项公式
性质:
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)
第一类斯特林数(斯特林轮换数)
一个轮换就是一个首尾相接的环形排列。我们可以写出一个轮换
递推式
边界是
贝尔数
递推公式:
$$ B{n+1}=\sum{k=0}^n\binom{n}{k}B_{k} $$
欧拉数
在计算组合中,欧拉数(Eulerian Number)是从
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))); }
等幂求和
预处理逆元 预处理组合数
$\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^i
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} $$
Comments NOTHING