组合基础
OI 中的组合,基本指组合计数。组合极值一般是贪心题或者 dp 题。
【组合数】
组合数
注意:求逆元前,请一定判断清楚,是否可能不存在逆元!!!
-
。c[n][m] = c[n - 1][m] + c[n - 1][m - 1];
这个方法主要问题在于空间。
优点:可以把
c[1 ~ n][1 ~ m]
全部求出来,好写。缺点:空间大。
复杂度:
。适用情况:
都小。 -
。问题:我们不可能把分子乘完再除以分母,会爆的。
方法一:
。 但是这个方法可能会爆。方法二:求出
的逆元。然后把除换成乘。一路直接乘过去,边乘边模。复杂度:算一次
。适用情况:
小。 -
。只要能求出阶乘的逆元,就可以
计算。我们考虑
和 互相转化。 。所以
。我们先欧拉函数暴力计算
的逆元,然后从大往小推出所有阶乘逆元。注意:我们这里是可以从
推 ,而不是 推 。优点:
预处理之后,每次询问 。复杂度:
。适用场景:
可行,需要多次查询。 -
卢卡斯定理(Lucas)。
二项式定理:
。引理:对
, 为质数, 。引理证明:
,分子有一个 ,分母没有 。卢卡斯定理:
。(若
中 ,则 )证明:
记
。又
而
。所以
发现
的 次项,一定是从左边括号选出 次项,右边括号选出 次项,然后相乘得出的。所以
的 次项的系数一定是 。而从二项式定理的展开中知道,
的 次项的系数应该是 。所以
。证毕。
复杂度:
。适用场景:
非常大, 可行。或者 ,不能直接求逆元(不能保证互质),用卢卡斯定理转化。
三角形个数 = 任取三个点的方法数 - 三点共线个数。
总数:
行的三点共线:
列的三点共线:
斜的:
考虑枚举所有点,对于一个点,枚举所有斜率,看这条线上有多少个点,然后用组合数求出来。
但是发现一个斜率可能有很多个点所得出的答案一样。
于是我们改一下顺序:先枚举所有斜率,然后对于所有可以放上这个斜率的点,求出这个斜率上所有点,然后再减去。
斜率可以看做一个长方形的对角线。于是我们枚举这个长方形的长
在每一个长
另外,还要注意,长方形有两条对角线,所以每次减的时候要减两份。
其实就是卡特兰数。
考虑把问题对应成一个
把向右移动一格看做是在前面放一个 1,向上移动一格看做是放一个 0。那么移动到右上角就相当于我们取完了所有 0 和 1。每条移动的路径都和一个字符串一一对应。
条件 “任何前缀中 1 的个数必须不少于 0”,就相当于从左下角画一条 45° 向右上角走的斜线,不能越过这条斜线。
把这条斜线整体上移一个,条件就变成了不能碰到这条斜线。
我们还是考虑总数减去不符合要求的数。
总数:
不符合方案(碰到斜线):
把这个方格表的左边加一列,并把斜线往左下角延伸一个。此时的斜线就连到了新方格表的左下角。
考虑所有不符合的方案,一定存在第一个点,碰到了斜线。
我们把这个点之前进行的所有步,都关于这条斜线做对称。
这样我们就得到了一条新路径:从新表左下角的上面一格出发,走到右上角。
我们发现,每一条这种路径,都与一条不符合要求的路径一一对应。并且,这种路径一共走了
所以,这种路径的数量是
因此,答案就是
插板法。
注意:
两种情况:
-
一左一右。
假设高度
。则 的楼高度取值 。我们发现,只要取出了
个高度,其排列方式已经固定了。所以,这就是一个 “可重组合”。从
种里面选 个,答案之后另外三个部分都差不多,求完四块之后全部相乘,就是
高度为 的方案数。复杂度
。因为 预处理组合数(第三种), 枚举 的高度。 -
同侧。
显然,同左和同右是对称的。
这种其实就是只有三个部分——
中间夹着的一定高度都是 。
【容斥原理】
有三个集合
例如,
容斥原理:
证明方法考虑归纳法。
容斥原理的题目一般长这样:
符合条件
对
符合
(1):答案为
(2):答案为
而全集一般都很好求。所以情况(1)和情况(2)可以视为等价的。
不妨称
容斥原理的代码:
写一个子集枚举,传参数记录选了多少个集合交起来。然后根据参数判断当前的答案是正是负。
记
则
这个并集是不好算的,但是交集很简单。
我们可以搜索——搜索出所有若干个质数相乘的所有次数为
如果只有一次询问,可以直接多重背包加单调队列优化,但是有多次询问。
记
记
因为硬币种数很少,所以每次询问求一次容斥都没压力。
一个东西选超量:先把它取完,再多取一个,最后随便选。
如果不要求每人至少拿一个,我们可以先把第一个分给所有人,然后分第二个…… 分每一个之间相互独立,分步计数。
如果要求每人至少一个,当前每个人是否拿到了就会影响后面的特产分发,不能分步计数。
但是,我们可以考虑反面:至少有一个人没有特产。
想要的:
另外注意到,无论是哪两个同学没分到,答案都相等。所以我们不需要真的枚举所有子集。
一个人没分到:把所有东西都分给别人。
分步考虑三个条件。
-
为第 种颜色不用。想要的是所有集合并起来的补集:所有颜色都用过。 剩下 种颜色随便染的方法数。复杂度贡献乘
,无论是选第 种颜色,还是选第 种颜色,答案都是一样的。 -
有
种颜色可选。 为第 行无色。所有集合的并集的补集:每一行都有色。 行 列染色,不要求每行有色。 -
行 列 种颜色,只需每列有色。不考虑另外两个条件。 是某一列有色的情况数:一列 个,每个有 种染色方式(包括不染),去掉每一个都不染的情况。一共
列, 种方法。
用两次容斥,去掉两个条件。
//用x种颜色染色的方法,仍要求行列非全无色,但x种颜色不必都用过
long long cnt(long long x) {
long long ans = 0;
// 其中i行可以有颜色,即某n-i行无色
for (long long i = n, t = 1; i >= 1; i--, t *= -1)
ans = (ans + fpow((fpow(x + 1, i) - 1)/*一列全部方案减去一种全无色*/, m)/*所有列非全无色*/ * t * cmb(n, i) % p + p) % p;
//X种颜色不必都用过(但每行每列必须有色)=X种颜色涂n行(颜色不必都用每行不必有色但每列必须有色)-X种涂n-1行(颜色不必都用每行不必有色但每列必须有色) + X种颜色涂n-2行(颜色不必都用每行不必有色但每列必须有色)- ....
//X种颜色涂i行(颜色不必都用,每行不必有色,但每列必须有色)已经足够简单,方法数是 [(X+1)^i - 1]^m
return ans;
}
for (long long i = c, t = 1; i >= 1; i--, t *= -1)
ans = ((ans + cmb(c, i) * cnt(i) * t) % p + p) % p;
//ans = C种颜色不必都用过(但每行每列必须有色) - C-1种颜色不必都用过(但每行每列必须有色) + C-2种颜色不必都用过(但每行每列必须有色) - ....
考虑所有符合条件的路径,一定有 “第一个碰到斜线的地方”。(至少在终点碰到了)
这两个部分分别是更小的卡特兰数。
当出入栈序列固定,最终序列也就确定了。
出入栈序列只要求每个前缀中,出栈个数小于等于入栈。
这就是卡特兰数。
简化题意:
给出一个音阶集合
要求选出
问有多少组
三个条件:不同、非空、
设
分步。
-
任选
,只要求不同非空即可, 。 -
选
。对于一个音阶 ,如果在选出的 中出现奇数次,必须选;否则必须不选。考虑特殊情况:
和之前的重复了,或者是空集。-
空,意味着前 个已经满足了所有条件。因为 “
个有一个空集” 和 “ 个刚好满足所有条件” 一一对应,所以一共有 个这种情况。 -
和之前的重复了(显然这种情况和 1 类没有重复),意味着把 和与它重复的集合去掉,又可以满足所有条件。考虑这个对应关系。
显然
个片段含一对重复,可以唯一对应到 里面。但是
对应到很多个 “ 个含一对”,因为 含的一对相同片段有 种选择。所以最后有
种这个情况。
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!