定义
简单的定义是组合数学就是在学用来解决和组合相关问题的一个工具箱。复杂的一点的定义是,组合数学的主要内容可以分为四大类:计数类,生成类,证明类,设计类。
排列组合是组合数学中的基础。排列就是指从给定个数的元素中取出指定个数的元素进行排序;组合则是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序。排列组合的中心问题是研究给定要求的排列和组合可能出现的情况总数。排列组合与古典概率论关系密切。
排列数公式计算方法
(1)定义式
公式简记为:
组合数公式计算方法
(1) 定义式
公式可以简单记为:
或者:
表示从 (n) 个数中选 (m) 个数的方案数
(2) 模意义
适用于(nle1e9,mle 1e5)的较大模运算,小的也可以
首先根据定义式我们可以将((n-m)!)全部消去
得出式子
进而求得
(3) 高精法
适用于答案过大时的计算
依旧是(2)中的第一个式子,通过高精乘法来实现,如果有多个相加还要加上高精加法,难度不大,好记
代码
(4) (Lucas) 定理
(Lucas) 定理用于求解大组合数取模的问题,其中 (p) 必须为素数。正常的组合数运算可以通过递推公式求解,但当问题规模很大,而模数是一个不大的质数的时候,就不能简单地通过递推求解来得到答案,需要用到 (Lucas) 定理。
可以大量减少运算量和时间
预先处理好(0-(mod-1))的模意义下的阶乘和逆元,求得时候(O(1))代入即可
一个应用公式为
实际应用时的公式为
其中(Lucas(n,0)=1)利用这个公式进行返回即可
固定模数代码
多重询问,非固定模数代码
其余待添加……
组合数思想方法
- 插空法
(1)空隙内必须有值的情况
当遇到一些有特殊限制的,并且可以重复取的问题时,我们可以用这个方法进行求解。
假设一个问题,有一个数 (g),要求求 (k) 个数组成 (g) 的方案数
这个问题就是插空法的经典例子了,首先可以把 (g) 个数想象成 (g) 个小球,小球之间一共有 (g-1) 个空隙,要把这 (g) 个小球分成 (k) 份,即在这空隙中插上 (k-1) 个隔板,转换成求插空的方案数
也就是求
的值
(2)空隙内可以没有值的情况
假设有 $n $ 个篮球,要求分给(k)个人,每个人可以没有篮球
那么就是有 (k-1) 个隔板来插空,但是可以同时排列在同一个空隙中,那么就是求 (n+k-1) 个位置中,选出 (k-1) 个位置来填充
公式记为
- 二维求放置方案
1、(n imes n) 的矩阵上放置 (n) 个车,每个车不相同,每行每列只能放置一个车求放置方案数
第一行有 (n) 种选择:第二行有 (n-1) 种选择,第三行 (n-2) 种选择(...)第 (n) 行有一种选择
公式为
2、(n imes n) 的矩阵上放置(k)个车,求放置方案数
从 (n) 行中选 (k) 行,(n) 列中选 (k) 列
公式为
为什么要有 (k!) 在我的理解中因为只是位置确定了,但是每个位置放哪一个小车并不知道,所以一共共有 (k!) 中在上面摆放的可能
3、(n imes m)的矩阵上放置 (k) 个车,求放置方案数
合在上面的类似,即
4、(n imes m)的矩阵上放置 (k) 个车,要求不能同行或者同列,求放置方案数(自己推得式子,可能会出错,欢迎纠错)
我们可以把(n)分成两份,在两个矩形中找弄式子
注意此时(0!=1)
5、关于不规则矩阵的排列,详情课件P1350
典型例题
P2822 [NOIP2016 提高组] 组合数问题
分析
-
30pts 暴力枚举,一会就溢出了
-
70pts 运用组合公式的推论
可以直接递推求解,唯一要注意的是要进行初始化
- 90pts 运用取模防止溢出的方法加速运算
最后判断一下是都满足 (0) 即可,最后存一个数组里一个一个加求和
- 利用杨辉三角优化
我们通过杨辉三角的方法来把所有的方案数都列出来可以得到这么一个图形
通过这个式子很简单的可以发现(行是 (n) 列为 (m) )
于是乎,你就可以快乐的用 (O(1)) 做完这个题
代码实现
P1313 [NOIP2011 提高组] 计算系数
思路
通过枚举 $ kle 5 ,a=1$的所有系数排列发现是一个杨辉三角
并且(x^ny^m)的系数所在的位置为((k+1,k-n+1))
最后的系数乘上(a^nb^m)即可
注意开$long long $
代码实现
P6057 [加油武汉]七步洗手法
思路
首先因为是完全图的缘故,那么由各个顶点组成的三角形一共有
其次看题目,要找同色三元环的数量,并且根据提示,所给的 (m) 条边均没有组成自环的,所以只可能是黑色三元环
那么首先求出白色边会破坏的三角形数量,每一个为((n-2))个三角形,那么一共破坏的是
但是其中我们会发现的是,每当一个点所连接的白边数(poi_igeq 2)时,都会出现重叠的情况,并且每次重叠了(poi_i-1)个,所以每一个点一共重叠考虑的是
条边
那么转化为公式就是一共重叠考虑的边为
最后减去白色所影响的边,加上重复考虑的边,即为答案
代码实现
P1066 [NOIP2006 提高组] 2^k进制数(重点+高精)
思路
因为是高精,所以就直接重点讲解一下=_=
先看一看题意
设 (r) 是个 (2^k) 进制数,并满足以下条件:
-
(r) 至少是个 (2) 位的 (2^k)进制数。
-
作为 (2^k) 进制数,除最后一位外,(r) 的每一位严格小于它右边相邻的那一位。
-
将 (r) 转换为二进制数 (q) 后,则 (q) 的总位数不超过 (w)。
在这里,正整数 (k,w) 是事先给定的。
问:满足上述条件的不同的 (r) 共有多少个?
首先把重点锁定在最高位上即可
题目给出的定义是,把转化后的二进制串一共分成了 (w/k) 个整段,也许还有一个长度小于 (k) 的段
一、先来讨论一下恰好分成 (w/k) 段的情况
这种情况下,每一段可以选择的数为(0…2^k-1)中的一个
并且可以选择 (2-w/k)个数来拼凑,可以发现这是一个有序的,符合组合数的性质,就可以得到公式
二、当有一段 (<) (k) 的时候
这个情况,可以先看一看最高位一共占了几个二进制位
通过简单分析可以得到,一共是(len=w)%(k)的长度
那么可以取到的数有 (1…2^{len}-1)
因为如果有前导 (0) 会导致和前面的重复,所以不予考虑
所以就在选了前(w/k)的数的基础上再+1,构成最终满的排列
因为在最高位选了数 (i),所以就只能在(2^k-1-i)中选择
因而得到公式
求解就可以啦,注意高精即可
代码实现
P1771 方程的解
思路
插空法+高精乘法,详情请看上方,注意开$long long $
代码实现
P1350 车的放置
思路
直接根据二维内的公式进行分离并求式子,分成 (a imes (b+d)) 的和 (c imes d) 的两个矩阵,推出式子
注意此时(0!=1)
为什么要有 (b+d(k-i))?
因为在第二个矩形中肯定已经找完了((k-i))行,不能再在第一个矩形里面找了,所以要把这些情况全部减去
代码实现
10235. 「一本通 6.6 练习 6」序列统计
思路
$ Lucas$ 定理的实际应用
也就相当于把 (n) 个相同的球放到了(R-L+1)个盒子里,球可以不放完,盒子可以为空
那么再加一个盒子,把没有放的都放到那个盒子里面
那么这个题目就相当于在(R-L+2)个盒子中放上 (n) 个球的方案
也就是 (n) 个篮球,有(R-L+1) 个隔板,可以挨着排列,求方案数
经典的隔板法
简单理解为插板法的第二种方法
得到公式为
模数较小用(Lucas)定理做即可