组合数学总结

数学是毒瘤


组合数学总结。

如果说数论是数学的基础,那么组合数学往后就是高阶了。这之后的数学不再像数论那么板子,而是变得需要更多的推理和组合了。知识很简单,难的是应用。

本来还有什么容斥原理,看不懂,于是没放


初始化

为了方便快速求排列组合,我们需提前预处理阶乘和阶乘的乘法逆元。

fac[i] 表示 i 的阶乘,inv[i] 表示 i 的阶乘 的乘法逆元。

inv[i]i 的阶乘 的乘法逆元,不是 i 的乘法逆元!

2024/3/17 upd.

注意:若 n 的规模超过 106 级别,请勿预处理 inv[i],而是即时计算!

注意:若 n 的规模超过 107 级别,请线性求逆元!公式:inv[i]=inv[i+1]×(i+1) mod MOD。——2024/5/19 upd.

void init() {
	fac[0] = inv[0] = 1;
	for (int i = 1; i < MAXN; i++) {
		fac[i] = fac[i - 1] * i % MOD;
		inv[i] = power(fac[i], MOD - 2, MOD);
	}
}

一般情况下,数论题都有一个 MOD 值,否则可以传参 p 表示模数。

排列数 Anm

排列数的计算公式如下:

Anm=n!(nm)!

inline int A(int n, int m, int p) {
	if (n < m) return 0;
	return fac[n] * inv[n - m] % p;
}

组合数 (nm)

组合数的计算公式如下:

(nm)=n!m!(nm)!

inline int C(int n, int m, int p) {
	if (n < m) return 0;
	return fac[n] * inv[m] % p * inv[n - m] % p;
}

排列数和组合数都只需 O(n) 的预处理便可 O(1) 查询。

若需要即时求组合数,可以根据公式直接记忆化搜索:

int C(int n, int m) {
	if (m == 0 || m == n) return 1;
	if (cc[n][m] != 0) return cc[n][m];
	return cc[n][m] = C(n - 1, m) + C(n - 1, m - 1);
}

组合数性质

(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)

通过组合分析一一考虑 S=a1,a2,,an+1k+1 子集数可以得证,在恒等式证明中比较常用。

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

通过定义可以证明。

(12)i=0n(nii)=Fn+1

Lucas 定理

n,m 过大、超出数组的范围时,我们需要用 Lucas 定理求组合数。模数必须为质数。即对于质数 p,有:

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

易知,(nmodpmmodp)n,m 范围一定小于等于 p,可以直接求解;(n/pm/p) 可以继续递归求解。当 m=0 时,返回 1,递归结束。

int lucas(int n, int m, int p) {
	if (m == 0) return 1;
	return C(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}

二项式反演

二项式反演用于解决“某个物品恰好若干个”这类计数问题。

直接摆公式。证明需要用到前文提到的组合数定理。

形式 1

fn 表示恰好 n 个的方案数量,gn 表示至多 n 个的方案数量,则:

gn=i=0n(ni)fifn=i=0n(1)ni(ni)gi

形式 2

fk 表示恰好 k 个的方案数量,gk 表示至少 k 个的方案数量,则:

gk=i=kn(ik)fifk=i=kn(1)ik(ik)gi

错排问题

Dn=(n1)(Dn1+Dn2)

posted @   Laoshan_PLUS  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示