组合数学
基础概念
加法和乘法原理
加法原理
同一步下的不同选择,可以通过累加得到方案数。
乘法原理
整个流程的方案数可以由每一步的方案数相乘得到。
有了加法原理和乘法原理,就可以解决一些没有选择导致分支的问题了。
例题1
有 \(n\) 个篮子,第 \(i\) 篮子有 \(a_i\) 有水果,每个水果各不相同,问每个篮子选出一个得到的水果的方案数。
解答:
用加法和乘法原理,那么每个篮子选出的方案数为 \(a_i\) ,总共就是 \(\prod a_i\) 种方案。
排列和组合
排列数
从 \(n\) 个不同元素中选出 \(m\) 个,按照一定顺序排列,简而言之就是选出一个数列的方案数。
组合数
从 \(n\) 个不同元素中选出 \(m\) 个的方案数,换句话就是选出一个集合的方案数。
其实排列数可以看做在选出 \(m\) 个数后还有对这 \(m\) 个数做一个全排列,所以多一个 \(m!\)
因为组合数我们用得多一点,所以我们一般用二项式系数来表示组合数,也就是说:
然后定义一些离谱的情况: \(m>n\) 或者 \(m<0\) 时, \(\binom{n}{m}=0\)
多重组合数
多重组合数和多重集排列数
多重集合,也叫可重集。一个多重集合 \(S=\{a_1\cdot n_1,a_1\cdot n_2,...,a_m\cdot n_m\}\) (\(n_i\) 表示元素个数, \(a_i\) 表示元素)的排列数(也被称为多重组合数):
相当于是所有数的全排列数再除去相同元素的全排列数。
顺便补充一嘴:
多重集组合数
一个多重集合 \(S=\{a_1\cdot n_1,a_1\cdot n_2,...,a_k\cdot n_k\}\) 的组合数,就是从中选出 \(r\) 个,得到不同可重集的方案数。
这个怎么弄?先来个简单的的,我们使 \(r<n_i\)。
这个我们考虑用插板法来求。可以看做我们现在有 \(r\) 个小球,然后现在往里面插板来分组。
最初的时候,我们有 \(r\) 个球,那么我们有 \(r+1\) 个位置是可以插空的。当我们插入了一个板子之后,我们可以插入的位置就又多了一个,后面就同理了。
于是乘法原理加上除去板子的全排列可以得到答案:
现在考虑把 \(r<n_i\) 的限制拿掉,怎么做?
这个要容斥原理!但是在这篇博客里我们还没有学!超纲了,我们等会讲容斥的时候再说。
不相邻排列
\(1\to n\) 个自然数中选出 \(k\) 个,使得他们互不相邻的方案数?
答案是 \(\binom{n-k+1}{k}\) ,相当于是留了 \(k-1\) 个空加在每两个被选择的位置中间。
组合恒等式
1.对称式
证明:
从组合意义上来说容易证明。因为你 \(n\) 中拿 \(m\) 个等价于有 \(n-m\) 个不拿。
2.二项式定理
证明:
从组合意义来证明。
我们把 \((x+y)^n\) 看作是有 \(n\) 个 \((x+y)\) 相乘,那么得到一个 \(x^ay^{n-a}\) 相当于是从 \(n\) 个 \((x+y)\) 中选出 \(a\) 个 \((x+y)\) 中的 \(x\) 相乘,那么结果的多项式中就有一项是 \(\binom{n}{a}x^ay^{n-a}\) 。所以的这种项都满足这种情况,那么公式可得。
Q.E.D.
其实不一定要求必须是两元的,多元的也是同理。
然后我们可以得到多项式定理:
证明:
同二项式定理证明,对于 \(x_1^{n_1}x_2^{n_2}...x_m^{n_m}\) 这一项的系数为 \(\binom{n}{n_1}\binom{n-n_1}{n_2}...\binom{n-n_1-n_2-...-n_{m-1}}{n_m}\) 。
展开发现可以抵消一些东西,于是上面的系数就等于:
Q.E.D.
3.递推式1
帕斯卡定理,你也可以说是杨辉三角。我们知道 \((x+y)^n\) 得到的多项式是系数满足杨辉三角的,我们知道了二项式定理的话,发现这个东西实际上是组合数,所以实际上是组合数的同层展开是满足杨辉三角的。但是证明的话显然不能这么证明。
证明:
我们一个数一个数看这个数是否选取,假设现在已经看了 \(n-1\) 个数,选了 \(x\) 个数。我们考虑如果得到 \(\binom{n}{k}\)
那么接下来这个数选或不选分别造成 \(1\) 和 \(0\) 的贡献,也就是说:
如果接下来这个数选,那么只有 \(x=k-1\) 的情况符合条件。否则只有 \(x=k\) 的情况符合条件。于是加法原理把两种情况的方案数加起来即可。
Q.E.D.
4.特殊的二项式定理
实际上是 \((1+1)^n\) ,当然也可以从组合意义上证明。
实际上是 \((1-1)^n\) ,我称之为第一类二项式反演。
5.递推式2
按定义来就没了,简单提一下。
6.积式
定义展开左边上下分子分母同乘 \((n-k)!\) 即可证明。
7.变下项求和式
证明:
Q.E.D.
证明和上面差不多,就不证了。其实你想拆可以一直这么拆。
8.变上项求和式
证明:
采用组合分析。
指定 \(n+1\) 个数的集合 \(S=\{a_1,a_2,...,a_{n+1}\}\)
先考虑右边的组合意义,即从 \(n+1\) 个数中选出 \(k+1\) 个。
左边的组合意义:相当于是总共 \(n+1\) 种不累加的情况的加法原理。
第一种:在指定必须选择 \(a_1\) ,然后从剩余的 \(n\) 个数中选择 \(k\) 个,方案数 \(\binom{n}{k}\)
第二种:在指定必须不选择 \(a_1\) 而选择 \(a_2\) ,然后从剩余的 \(n-1\) 个数中选择 \(k\) 个,方案数 \(\binom{n-1}{k}\)
第三种:在指定必须不选择 \(a_1,a_2\) 而选择 \(a_3\) ,然后从剩余的 \(n-2\) 个数中选择 \(k\) 个,方案数 \(\binom{n-2}{k}\)
第 \(n+1\) 种:在指定必须不选择 \(a_1,a_2,...,a_n\) 而选择 \(a_{n+1}\) ,然后从剩余的 \(0\) 个数中选择 \(k\) 个,方案数 \(\binom{0}{k}\)
总体的组合意义 \(\sum_{i=0}^n{\binom{i}{k} }\) 等价于从 \(n+1\) 个数中选出 \(k+1\) 个,那么等式左右两边组合意义相同,等式成立。
Q.E.D.
9.积和式
证明:
指定集合 \(A=\{a_1,a_2,...,a_m\}\) 和 \(B=\{b_1,b_2,...,b_n\}\)。
右边问题等价于从 \(A,B\) 两个集合中选出 \(r\) 个的方案数。
左边问题等价于:
对于 \(k\in [0,r]\),先在 \(A\) 中先取出 \(k\) 个,然后在 \(B\) 中选出 \(r-k\) 个的总方案数。
即 \(A,B\) 中总共选出 \(r\) 个的方案数。
所以左右两个问题组合意义等价,等式成立。
Q.E.D.
10.第二类二项式反演
证明:
已知:\(g(n)=\sum_{i=0}^n(-1)^i\binom{n}{i}f(i)\)
则:
Q.E.D.
然后我们还可以得到一个扩展:
证明:
令 \(G(n)=(-1)^ng(n)\) ,有:
若 \(f(n)=\sum_{i=0}^n(-1)^i\binom{n}{i}G(i)\) 成立,有 \(G(n)=\sum_{i=0}^n(-1)^i\binom{n}{i}f(i)\)
即
当 \(n\) 为偶数,则 \(n-i\) 与 \(i\) 奇偶性相同,有 \(g(n)=\sum_{i=0}^n(-1)^{n-i}\binom{n}{i}f(i)\)
当 \(n\) 为奇数,则 \(n-i\) 与 \(i\) 奇偶性相反,同样有 \(g(n)=\sum_{i=0}^n(-1)^{n-i}\binom{n}{i}f(i)\)
由此有 \(g(n)=\sum_{i=0}^n(-1)^{n-i}\binom{n}{i}f(i)\)
Q.E.D.
圆排列
考虑 \(n\) 个人围成圆的圆排列方案数为 \(Q^n_n\) 。我们发现对于一个圆,从每个地方断开都可以形成一个新的排列,所以:
\(Q_n^n\times n=A^n_n\Rightarrow Q^n_n=\frac{Q^n_n}{n}=(n-1)!\)
所以 \(Q^m_n=\frac{A^m_n}{m}=\frac{n!}{r(n-r)!}\)
错位排序
设 \(f(n)\) 表示将 \(n\) 个编号为 \(1,2,...,n\) 的物品,放到编号为 \(1,2,...,n\) 的位置中,使每个物品放置的位置的编号与物品的编号都相同的方案数。
我们考虑递推,考虑目前放置第 \(n\) 个物品,先暂时放在第 \(n\) 个位置,而保证其他 \(n-1\) 个物品都放在 \([1,n-1]\) 的位置。然后考虑前面的一个物品和第 \(n\) 号物品交换位置,可知 \(f(n)\) 只能由两种情况递推而来。
第一种情况:前面的 \(n-1\) 个物品全部错位。这个直接就是每个物品都可以换。总共 \(n-1\) 种交换方法。
第二种情况:前面 \(n-1\) 个中除一个物品外全部错位。\(n\) 必然与这个不错位的物品换位,这个不错位物品有 \(n-1\) 种可能。
那么可得递推式:
鸽巢原理
假设有 \(n+1\) 个物品,那么将物品分为 \(n\) 组后,至少有一组含有两个及以上的物品。
证明:
假设每个分组都只有至多 \(1\) 个物品,那么最多有 \(n\) 个物品,与有 \(n+1\) 个物品的事实矛盾。
由此得证。Q.E.D.
一个扩展:
将 \(n\) 个物品分为 \(k\) 组,至少存在一个分组含有大于等于 \(\lceil\frac{n}{k}\rceil\) 个物品。
同样可以反证,简单就不证了。
容斥原理
有一个集合的集合 \(A=\{S_i\}\) ,那么:
证明:
如果对于每个元素都保证其出现一次,那么上式正确。
现在考虑对于一个元素 \(x\) ,证明其出现次数为 \(1\) 。假设它在集合 \(T_1,T_2,...,T_k\) 中出现。
那么其出现次数为:
可知出现次数为 \(1\) 。Q.E.D.
容斥原理的补集形式
右边容斥计算即可。
容斥原理一般化
对于两个关于集合的函数 \(f(S),g(S)\) ,如果:
那么有:
证明:
我们知道,对于一个关于集合的函数 \(F(P)=\sum_{T \subseteq (P)} (-1)^{|P|-|T|}\),有:
那么我们就有:
Q.E.D.
还有一个倒过来的推论(补集形式)
如果:
那么有:
Min_max 容斥
对于 \(n\) 长全序序列 \(\{x_i\}\) ,\(S=\{1,2,...,n\}\),有:
证明:
由于全序的对称性,我们可以知道 \(min\) 和 \(max\) 互换的话,效果也是一样的,所以我们只考虑证明第一个式子。
考虑构造一个系数 \(a_i\),满足:
那么:
解释一下,这里是对于每个元素统计其贡献,对于第 \(i\) 大的数,我们可以知道其在所处集合作为最小值的集合的大小小于等于 \(i\) 。然后我们可以枚举集合的大小,显然比这个数大的有 \(i-1\) 个,我们从中再选出 \(j-1\) 个和当前这个数组成集合,那么上式可得。
然后我们知道,当 \(\sum_{j=1}^ia_j\binom{i-1}{j-1}=[i=k]\) 时,则构造成立。
令 \(g(n)=[n+1=k],f(n)=a_{n+1}\) 那么:
由二项式反演:
因此:
Q.E.D.
其实 min_max 容斥
在期望意义下也满足:
由期望线性性可知。
再论多重集组合数
我们前面提到过这个问题是需要容斥原理的。现在我们已经可以解决这个问题了。
回顾一下问题:一个多重集合 \(S=\{a_1\cdot n_1,a_1\cdot n_2,...,a_k\cdot n_k\}\) 的组合数,就是从中选出 \(r\) 个,得到不同可重集的方案数。每个数被选出 \(x_i\) 个。
设一个集合 \(S_i\) 表示不满足 \(x_i\le n_i\) ,即满足 \(x_i\ge n_i+1\) 的集合。
那么答案为:
后面那半部分我们容斥计算:
意义就是提前为其留出一些空间使其满足条件。
那么:
那么就可以切掉这个题了
但是这个题还有一个小技巧。
发现范围巨大,不好直接算组合数,但是 \(n\) 很小,我们把组合的求和转换为与 \(n\) 相关的算法。具体转换类似下方的做法。
卡特兰数(Catalan)
卡特兰数 \(Cat_n\) ,是下问题的答案:从 \((0,0)\) 出发,可以按照向量 \((1,0)\) 和 \((0,1)\) 游走,不越过(可以碰到)第一象限角平分线的情况下,到达 \((n,n)\) 的方案数。(就是只能在这条线下方走)
我们通过解决这个问题可得到卡特兰数的公式。
不越过第一象限角平分线 \(y=x\) ,等价于不触碰 \(y=x+1\) 。
然后你发现如果你碰到了直线 \(y=x+1\) ,那么可以发现从这个触碰点到 \((n,n)\) 的方案数和到 \((n-1,n+1)\) (\((n,n)\) 关于 \(y=x+1\) 的对称点)的方案数相同,因为在两边走是对称的。然后我们知道到达 \((n-1,n+1)\) 必然经过 \(y=x+1\) ,所以只需要到达 \((n,n)\) 的方案数减去到达 \((n-1,n+1)\) 的方案数即可。
即 \(Cat_n=\binom{2n}{n}-\binom{2n}{n-1}\)
通项公式
递推公式
然后初始状态 \(Cat_0=Cat_1=1\)
递归公式
证明:
对于 \(2n\) 长的括号序列,如果最后一个右括号与第 \(i\) 个左括号匹配,那么前 \((i-1)\) 个左括号的匹配肯定构成一个合法括号序列。这个 \(i\) 满足 \(1\le i\le n\) 。那么公式可得。
Q.E.D.
应用
我们发现其实对于所有的可以转化为如下问题的问题,都可以考虑卡特兰数列:
长度为 \(2n\) 的合法括号序列计数。
这个问题可以抽象上坐标轴,即从 \((0,0)\) 通过向量 \((1,1)\) 和 \((-1,-1)\) 到达 \((2n,0)\) 且不越过 \(x\) 轴。这个和我们上面的那个问题是等价的,通过关于 \(y=-1\) 对称可以得到相同的答案。
当然,如果遇到等价于我们最初提到的问题的问题,那么也是可以考虑卡特兰数列的。
我们看一些例子来判断一下:
1.有 \(2n\) 个人排成一行进入剧场。入场费 \(5\) 元。其中只有 \(n\) 个人有一张 \(5\) 元钞票,另外 \(n\) 人只有 \(10\) 元钞票,剧院无其它钞票,问有多少种方法使得只要有 \(10\) 元的人买票,售票处就有 \(5\) 元的钞票找零?
每有一个有 \(5\) 元的人进来,就多可以接一个 \(10\) 元的人,分别抽象成左右括号,那么符合卡特兰数列。
2.一个栈,加入顺序为 \(1,2,...,n\) ,问合法出栈顺序的方案数。
左右括号分别代表入栈和出栈,符合卡特兰数列。
3.\(n\) 个节点,可以构成多少不同的二叉树?
假设 \(n\) 个节点的答案为 \(h(n)\)
于是我们每次固定根节点,有 \(h(n)=\sum_{i=1}^{n}h(i-1)h(n-i)\)
满足递归公式,符合卡特兰数列。
4.在圆上选择 \(2n\) 个点,求将这些点成对连接起来使得所得到的 \(n\) 条线段不相交的方案数。
选择两个点后其他点被分为两个部分,两边相互独立可以分治进行,满足递归公式,符合卡特兰数列。
5.对角线不相交的情况下,求将一个凸 \(2n\) 边形区域分成三角形区域的方案数。
这个和 \(4\) 的本质相同,就不再赘述。
例题
例题1
直接上公式就过了。
例题2
分析一下可以发现是卡特兰数列。我们可以发现一个结论,在奇数位放置一个数,那么它之前的数都小于它,它之后的数都大于他。然后可以分治处理,且当只有一个奇数位时,方案只有一个,因此满足卡特兰数列。
然后考虑怎么求这个卡特兰数,由于模数随机,我们不能逆元,递推公式就用不了了。
递归公式复杂度是 \(O(n^2)\) 的,显然不行。
那么只能考虑用通项公式求解。
把上下两个数约分一下。具体是把分子分母拆成乘法形式,开数组打个标记表示有多少个这个因数,然后它这些因数继续拆成质因数,最后统一计算每个系数即可。因为卡特兰数必定是整数,因此不用担心约分约不干净的情况。
这个可以增长一下经验,放个代码:
int n,mods;
inline int inc(int x,int y){
return (x+=y)>=mods?x-mods:x;
}
inline int dec(int x,int y){
return (x-=y)<0?x+mods:x;
}
inline int mul(int x,int y){
return 1ll*x*y%mods;
}
const int N=1e6+3;
int smallest[2*N];
std::vector<int>pri;
inline void Euler(){
smallest[1]=1;
for(int i=2;i<=2*n;++i){
if(!smallest[i]){
pri.push_back(i);
smallest[i]=i;
}
for(auto it:pri){
if(it*i>2*n) break;
smallest[i*it]=it;
if(i%it==0){
break;
}
}
}
}
int cnt[2*N];
inline int qpow(int a,int b){
int ans=1;
while(b){
if(b&1) ans=mul(ans,a);
a=mul(a,a);
b>>=1;
}
return ans;
}
int main(){
filein(a);fileot(a);
read(n,mods);
for(int i=1;i<=n;++i)
cnt[i]-=1;//分子
for(int i=n+2;i<=2*n;++i)
cnt[i]+=1;//分母
Euler();
for(int i=2*n;i>1;--i){
if(smallest[i]<i){
cnt[smallest[i] ]+=cnt[i];
cnt[i/smallest[i] ]+=cnt[i];
}
}
int ans=1;
for(int i=2;i<=2*n;++i){
if(cnt[i] and smallest[i]==i)
ans=mul(ans,qpow(i,cnt[i]) );
}
printf("%d\n",ans);
return 0;
}
斯特林数(Stirling)
第二类斯特林数
记作 \(\begin{Bmatrix} n \\ k \end{Bmatrix}\) ,或者 \(s_2(n,k)\) 。表示 \(n\) 个两两不同的元素划分为 \(k\) 个互不区分的非空子集的方案数。
递推公式
初始状态 \(\begin{Bmatrix} n \\ 0 \end{Bmatrix}=[n=0]\) 。
证明:
考虑新加入一个元素。
如果这个元素放在已经存在的非空子集中,有 \(k\begin{Bmatrix} n-1 \\ k \end{Bmatrix}\) 种方案。
如果这个元素单独新开一个非空子集,有 \(\begin{Bmatrix} n-1 \\ k-1 \end{Bmatrix}\) 种方案。
然后加法原理合并可得。Q.E.D.
通项公式
证明:
设 \(g(i)\) 为将 \(n\) 个不同元素放入 \(i\) 个不同集合中(可以为空集)的方案数,\(f(i)\) 为将 \(n\) 个不同元素放入 \(i\) 个不同集合(不可为空集)的方案数。
那么
第二个式子成立,是因为集合互不相同,先枚举启用几个集合,再枚举选择具体用哪些集合。
通过二项式反演:
于是有
同行计算
发现是一个卷积的形式,\(f(x)=\sum_{i=0}^n\frac{(-1)^i}{i!}x^i\) 卷积 \(g(x)=\sum_{i=0}^n\frac{i^n}{i!}\) 即可 \(O(n\log n)\) 的时间内求出。
第一类斯特林数
记作 \(\begin{bmatrix} n \\ k \end{bmatrix}\) 或 \(s(n,k)\) 。表示 \(n\) 个不同的元素划分为 \(k\) 个不同的非空轮换的方案数。
什么叫做轮换?相等于一个首尾相接的环。也就是说,对于轮换 \([A,B,C]\) ,其满足 \([A,B,C]=[C,A,B]=[B,C,A]\)。
递推公式
初始状态 \(\begin{bmatrix} n \\ k \end{bmatrix}=[n=0]\)
证明:
还是考虑新加入一个元素。
如果单独开一个轮换,那么有方案数 \(\begin{bmatrix} n-1 \\ k-1 \end{bmatrix}\) 种。
如果加入一个已经存在的轮换,那么可以考虑加在已经存在的数后面,有 \((n-1)\begin{bmatrix} n-1 \\ k \end{bmatrix}\) 种方案数。然后加法原理合并即可。
Q.E.D.
然后似乎没有什么好用的通项公式?
上升幂和下降幂
上升幂 \(x^{\overline{n}}=\prod_{i=0}^{n-1}(x+i)\)
下降幂 \(x^{\underline{n}}=\frac{x!}{(x-n)!}=\prod_{i=0}^{n-1}(x-i)\)
上升幂转普通幂
证明:
考虑归纳证明:
\(n=0\) 时,等式两边皆为 \(1\),等式成立
\(n=1\) 时,等式左边等于 \(x\) ,等式右边等于 \(x\) ,等式成立。
Q.E.D.
衍生公式:
由上式加上斯特林反演得
下降幂转普通幂
证明:
同样考虑归纳证明:
\(n=0\) 时,等式两边皆为 \(1\) ,等式成立
\(n=1\) 时,等式两边皆为 \(x\) ,等式成立
Q.E.D.
衍生公式:
同样是由上式加上斯特林反演得
其实这个式子也可以不用斯特林反演,我们直接按照组合意义来证明。
证明:
这是因为 \(m^n\) 的组合意义是将 \(n\) 个有区别的数放入 \(m\) 个有区别的集合,允许空集的方案数。上式子相当于先枚举盒子的个数,再枚举盒子的区别,再从 \(m\) 个集合中选出 \(i\) 个,然后再数放入。
当我们用这个来证明反演:
这里枚举范围可以取 \(n\) 的原因是我们认为 \(i\) 大于 \(n\) 时,式子值为 \(0\)。
而大于 \(x\) 的部分,\(\binom{x}{i}\) 取 \(0\) ,因此得到此式。
Q.E.D.
一个小小结论,按上面两个式子拆解易证:
反转公式
反转公式(1)证明:
Q.E.D.
反转公式(2)证明:
Q.E.D.
斯特林反演
上式中一二类斯特林数可以互换位置。
证明:
已知: \(g(n)=\sum_{i=0}^n(-1)^{n-i}\begin{bmatrix} n \\ i \end{bmatrix}f(i)\)
Q.E.D.