组合数学
你睁开眼睛,周身一片死寂,黑暗包裹着你;随后一片金色和蓝色缓慢升起,丝线缠绕,白色的裙袂在眼前飞舞。
你睁开眼睛,你看见了她,曾在去年的深秋与你立下约定。
她在叹息的盛夏向你发出邀请,在热烈的深秋与你相知相依。你记得的,她那时候说了什么?站在舞台之上,露出那种温柔的笑意,你很熟悉。她说:我们还会再见面,我还会站在你面前。
是啊,她答应你了,她说过还想见你。 你坐起身,去触碰她,但她笑着收回手。她看着你,眼睛一如既往美丽,闪烁绿色的荧光。她轻声说:再等等,与我相爱的人啊,再等候我吧。
我们一定会再见面的,在流光之奏中,在共鸣之音下。
然后她退后,星光缠绕着她,也缠绕着你。梦境将醒,但你并不惆怅——啊,你知晓的:你们马上要相见了。
组合计数
不会数数。
天依宝宝可爱!
常用恒等式
二项式定理:
杨辉三角(容易忘记用):
范德蒙德卷积(重要的):
证明考虑把 \(n+m\) 个元素分成两份,一份有 \(n\) 个,另一份有 \(m\) 个,然后等号右边就是直接组合数,等号左边是先考虑两份分别选几个在加法原理。显然两者是等价的。
范德蒙德卷积的形式就是上标固定,下标和固定,且 \(\sum\) 能从 \(0\) 取到满。
变式 #1:
变式 #2:
变式 #3:
证明:因为 \(\binom m i = \binom m {m-i}\),所以……就证出来了。
二项式反演:
令 \(f_i\) 为钦定有 \(i\) 个什么东西(\(\ge i\))的方案数,\(g_i\) 为恰好 \(i\) 个的方案数,则有:
其中 \(\infin\) 为题意中指定的上限。
令 \(f_i\) 为钦定最多 \(i\) 个(\(\le i\))的方案数,\(g_i\) 为恰好 \(i\) 个的方案数,则有:
严格证明见这里,但是因为这里是 OI 而不是 MO,所以只背过结论就可以了,并不需要证明。
记忆技巧:\(f\) 和 \(g\) 交换位置,\(\sum\) 不变,组合数不变,乘上一个 \(-1\) 的「\(n,i\) 中大的减小的」次方。
洛谷 P5505 | 二项式反演
思维难度:\(\color{#F39C11} 橙\) *900
以前拿容斥做过,但是,
组合意义天地灭,代数推导保平安。
另 \(f_i\) 为钦定 \(i\) 个人不选所得到的方案数,枚举钦定的是哪些人,考虑隔板法,有:
然后反演得到 \(g_i\) 为恰好 \(i\) 个人不选的方案数,于是 \(g_0\) 即为所求。
求 \(f_i\) 的复杂度为 \(O(m)\),求 \(g_0\) 需要 \(n\) 个 \(f_i\),所以总复杂度 \(O(nm)\)。
天依宝宝可爱!
洛谷 P4859
思维难度:\(\color{#52C41A} 绿\) *1600
怎么又是 dp,怎么 dp 总是在想不到的地方出现。
显然可以二项式反演,于是只需要求 \(f_i\) 表示钦定 \(i\) 组 \(a_x > b_y\) 的方案数。
但是发现这个东西好像不好直接组合数,所以考虑 dp。不过 dp 好像是三维的,不仅需要记录在两个序列分别遍历到了哪里,还要记录当前选了几对。
有一个很神奇的转化,注意到我们并不怎么关心两个序列分别遍历到了哪,只关心元素的相对大小,所以考虑把两个序列合并起来排序并标记每个元素来自哪个序列,这样就会惊奇地发现 dp 状态减少了一维,还更好转移。
令 \(g_{i,j}\) 为前 \(i\) 个元素,选了 \(j\) 对 \(a_x > b_y\) 的方案数,于是考虑当前元素属于 \(a\) 还是属于 \(b\),若属于 \(a\) 再考虑是否与之前未选择的 \(b\) 中元素构成 \(a_x > b_y\) 的关系即可。
天依宝宝可爱!
洛谷 P3214
思维难度:\(\color{#3498DB} 蓝\) *2000
神仙题。标「†」是神仙的地方。
那么就是要求 \(\{ 1,2,3\ldots,n \}\) 这个集合的若干个子集,†考虑转化为二进制表示 \(i\) 是否在所选子集内,那么就得到了 \(2^n\) 个集合,题意就转化成了在 \(2^n\) 个数中选 \(m\) 个满足以下条件:
- 选择的数两两不同。
- †所有数的异或和 \(=0\)。这是为了满足偶数的限制。
- 不能选 \(0\)。
令 \(f_i\) 为满足上面条件的选 \(i\) 个数的方案。
为了满足异或和为 \(0\),†可以这么想,考虑先随便选 \(i-1\) 个两两不同的元素,然后再选与这些元素的异或和相等的元素 \(x\),于是总方案数就是 \(\binom {2^n - 1} {i - 1}\)。这里先不考虑算重,因为显然每个方案被算了 \(i\) 次,最后除以 \(i\) 即可。
但是这样就无法保证满足条件 #1 #3 了,因为随便选的元素的异或和是什么我们不知道,于是考虑单步容斥把这两部分砍掉。
先看 #3,可以发现当且仅当随便选的元素异或和为 \(0\) 时,才会出现 \(x\) 选 \(0\) 的情况,而这正好对应了 \(f_{i-1}\) 的定义,于是需要减掉 \(f_{i-1}\)。
再看 #1,我们需要在减去不满足 #1 的方案的情况下,不能多减不满足 #3 的方案。考虑当且仅当随便选的元素中出现 \(x\) 时会出现这种情况,于是枚举每个 \(x\),那么剩下的 \(i-2\) 就需要满足异或和为 \(0\) 了,我们惊奇地发现正好对应的是 \(f_{i-2}\)。然后考虑对于一个 \(f_{i-2}\) 的方案,在 \(2^n - 1\) 个位置中已经确定了 \(i-2\) 个位置,于是还剩下 \(2^n - 1 - (i-2)\) 个位置可以放 \(x\)。所以要减去 \(f_{i-2} \times (2^n - 1 - (i-2))\)。
当然最后需要除以 \(i\)。
于是就得到了递推式:
天依宝宝可爱!
洛谷 P7322
思维难度:\(\color{#52C41A} 绿\) *1700
怎么想到的啊啊啊……
直接针对每个数统计出现次数,好像是可以做的,但是好像要容斥,好像复杂度还很不好保证。
考虑一个序列的滑动窗口 max,一定是分为若干段的,而且因为是排列所以每段都不同。所以只需要求 max 变化的次数就可以了。可以发现从 \([l,r]\) 到 \([l+1,r+1]\) 时 max 发生变化有这两种情况:
- \(\displaystyle \max _{i=l} ^{r+1} \{ a_i \} = a_{r+1}\)。
- \(\displaystyle \max _{i=l} ^{r+1} \{ a_i \} = a_l\)。
注意到两者其实是对称的,所以只需要求出第一个的答案然后乘 \(2\) 即可。
这部分数数是容易的。先枚举一个 \(a_{r+1}\)(令为 \(a_i\)),考虑这个窗口在什么位置,\(a_i\) 左边选 \(k\) 个 \(< a_i\) 的数是什么,以及窗口内和窗口外分别随便排列,则答案为:
于是这个乘 \(2\) 即可。
注意到我们只统计了变化量但没有统计初始量,所以还要加上一个 \(n!\)。
天依宝宝可爱!
洛谷 P2290
思维难度:\(\color{#F39C11} 橙\) *1100
Prüfer 序列,可以把一棵树转化成一个序列,且树和序列之间构成双射。构造方式是每次选当前剩余的所有点中,编号最小的度数为 \(1\) 的点,将它连向的父节点编号插入序列末尾,并将这个点以及这条边删除。最后整棵树只剩 \(2\) 个点的时候结束。
那么就得到了一个长度为 \(n-2\) 的序列。可以发现这个序列可以随便排,总能找到唯一对应的一棵树。
Prüfer 序列的一些性质:
- Prüfer 序列与无根树构成双射。
- \(n\) 个有编号节点任意连边能构成不同(不是本质不同)的树的个数为 \(n^{n-2}\);一个有 \(n\) 个节点的完全无向图的生成树个数为 \(n^{n-2}\)。
- 度数为 \(d\) 的点在 Prüfer 序列中恰好出现 \(d-1\) 次。
于是这个题就转化成了让 \(i\) 在长度为 \(n-2\) 的序列中出现 \(d_i - 1\) 的方案数,显然就是可重集上的全排列了。
但是不取模,所以要预处理分解质因数。
天依宝宝可爱!
CF559C
思维难度:\(\color{#FFC116} 黄\) *1400
做过,原题是 AT_dp_y。
啊…?原来这个题我也做过。细思极恐。
天依宝宝可爱!
洛谷 P3266
思维难度:\(\color{#3498DB} 蓝\) *2300
又是神仙题。
不过先不看这个题,而是考虑这样一个问题:
在一个平面坐标系上,给定起点 \((0,0)\) 和终点 \((n,m)\),以及两条直线 \(y=x+a\) 和 \(y=x-b\),求从起点走到终点且不经过两条直线的方案数。保证起点和终点都在两条直线之间。
如果没有限制,方案显然为 \(\binom {n+m} n\)。
如果只有一条直线的限制,考虑单步容斥。将不合法的路径翻折(仅翻折最后一次碰线之前的部分)后,可以发现这些路径都是从 \((0,0)\) 关于直线的对称点出发走到 \((n,m)\) 的,而且两者构成双射,所以直接减去这些路径就可以了。
那么考虑两条直线的情况。
懒得画图了,搬 题解 里的图吧。
如上图,可以发现这时候直接容斥是不好做的,因为极有可能算重。
那么不妨把不合法路径分为两类,令上面的直线为 \(a\),下面的直线为 \(b\),于是就可以根据一条不合法路径第一次碰的线的编号来区分了。这时候只需要找出其中一类怎么做就可以了,因为两类的做法是对称的。
再给一个定义。如果一条不合法路径碰线的顺序为 \(abbaab \ldots\),则记为 ABAB,即把连续的相同字母合并。
然后再放图。
现在只对以 A 开头的路径分析。
还是考虑翻折,把一条不合法路径沿直线 \(a\) 翻折,那么得到了新起点以及方案数,如图中粉色线。但是可以发现,如果翻折后的路径在 \(y\) 轴方向延伸地过长,翻折回来的时候就会先碰到直线 \(b\),再碰到直线 \(a\),如图中的青色线。这时候就要把这些路径再加回来,也就是把 BA 开头的路径加回来。
那么 BA 开头的路径怎么算呢?依然是翻折,考虑将一条这样的路径先沿直线 \(b\) 翻折,再沿直线 \(a\) 翻折,于是又得到了新的起点。但是类似的,可以发现这样会多算 ABA 开头的路径……
进而,在算 ABA 的时候会多算 BABA;在算 BABA 的时候会多算 ABABA……
不过可以发现,这个过程是有尽头的!因为每次的新起点 \((x,y)\) 会距离 \((0,0)\) 越来越远,直到 \(x > n \lor y > m\) 的时候就会结束,因为这时候就不存在任何满足条件的路径了。
注意到每次距离 \((0,0)\) 的相对位置至少增加 \(1\),所以复杂度是 \(O(n)\) 量级的,可以感性理解。
然后再回到这个题,发现事情远远没有那么简单()
先不考虑上面那个东西和这个题有什么关系。从题本身出发。
容易注意到 \(0 \le x_{i,j} \le m\),\(x_{i,j} < x_{i,j+1}\),而矩阵宽度正好为 \(m\),所以一行中的数一定是严格单增且只有一个数字不出现。所以可以这么 dp,设 \(f_{i,j}\) 为前 \(i\) 行,数字 \(j\) 不出现的方案数。转移考虑如何可以满足 \(x_{i,j} < x_{i-1,j+1}\) 的限制,有:
可以发现这个式子实际上就是算前缀和,所以可以转化为:
把这个转移拍到坐标系上,可以发现就是下图的合法路径条数。
然后再把斜线掰直,并将第 \(i\) 行的点右移 \(i\) 格;注意到最左边的向上的线掰不动,所以需要新建点,拆成向上向右两条线。于是就变成了我们想要的形式,也就是最上面那个图。
终点坐标为 \((n+m+1,n)\),两条直线分别为 \(y=x+1\) 与 \(y=x-(m+2)\)。
天依宝宝可爱!