组合数学相关总结
以下题目都是本专题的经典例题。如不特别说明,则题目来源为洛谷。
P3197 [HNOI2008]越狱
题意:
\(n\) 个格子,\(m\) 种颜色,求至少有两个相邻格子颜色相同的方案数。
思路:
补集转换,求不存在任何两个相邻格子颜色相同的方案数。乘法原理。
答案是
P6184 [USACO08OCT]Building A Fence G
题意:
长为 \(n\) 的木板,需要把木板切成四块,使得这四块可以围成面积不为零的四边形。求方案数。\(n\leq 2500\)。
思路:
原题当然很简单,我们考虑 \(O(n)\) 怎么做。
考虑从 \(n\) 个物品中插入3个隔板。总方案数为 \(\dbinom{n - 1}{3}\)。
减去不合法的方案数,即至少有一块长度大于等于 \(\left\lceil\dfrac{n}{2}\right\rceil\)。考虑枚举最长板的长度,再在剩下的长度中隔板法。注意最后乘上4。
最终答案
BZOJ3907 网格
题意:
从笛卡尔坐标系 \((0,0)\) 走到 \((n,m)\),中途保证 \(x\geq y\) 的方案数。
思路:
简单卡特兰数扩展。
P4071 [SDOI2016]排列计数
题意:
求有多少个 \(1\sim n\) 的排列,满足序列中恰好中有 \(m\) 个位置 \(i\),使得 \(a_i=i\)。
思路:
其中,\(D\) 是错位排列。
CF886E Maximum Element
题意:
有一个人用这个函数求序列的最大值。
int fast_max(int n, int a[]) {
int ans = 0;
int offset = 0;
for (int i = 0; i < n; ++i)
if (ans < a[i]) {
ans = a[i];
offset = 0;
} else {
offset = offset + 1;
if (offset == k)
return ans;
}
return ans;
}
求有多少个 \(1\sim n\) 的排列,使得它求出来的最大值不是 \(n\)。
思路:
先DP。\(f[i]\) 表示有多少个 \(1\sim i\) 的排列满足函数运行到最后还没有退出。
前缀和优化。
BZOJ4403 序列统计
题意:
长度在 \(1\sim n\) 期间,元素大小在 \(L\sim R\) 之间的单调不降序列的数量。
思路:
设 \(m = R - L + 1\)。
插板法,考虑枚举长度 \(i\),一共有 \(i\) 个物品,\(m - 1\) 个插板。当然插板可以为空。再用上指标求和公式。
P6669 [清华集训2016] 组合数问题
题意:
对于给定的 \(n,m,K\),有多少个 \(0\leq i \leq n,0\leq j\leq m\),满足 \(\dbinom{i}{j}\) 是 \(K\) 的倍数。
思路:
卢卡斯定理。
将 \(n\)、\(m\) 都转换成 \(K\) 进制数。搞数位DP。我们发现,\(K|\dbinom{i}{j}\) 当且仅当存在一位,\(i\) 的这一位比 \(j\) 的这一位小。
补集转换。设 \(f[i,0/1,0/1]\) 表示从高向低考虑了 \(i\) 位的方案数。在转移的时候保证上指标的这一位不比下指标小即可。
UVA11806 Cheerleaders
题意:
在 \(n\times m\) 的矩阵上放 \(K\) 个人。满足:
- 四个边上必须有人。
- 每个格子上至多放一个人。
- 每个人都有位置。
求方案数。
思路:
设 \(A_1\) 代表最上边没人的方案的集合,\(A_2\) 代表最下边没人的方案的集合,\(A_3\) 代表最左边没人的方案的集合,\(A_4\) 代表最右边没人的方案的集合。
求 \(|\overline{A_1}\cap\overline{A_2}\cap\overline{A_3}\cap\overline{A_4}|\)。
简单容斥原理。
CF449D Jzzhu and Numbers
题意:
给出一个序列 \(a_1,a_2,\ldots,a_n\),求满足以下条件的序列个数。
- $i_1<i_2<\cdots<i_k $
- \(a_{i_1}\& a_{i_2}\&\cdots\& a_{i_k}=0\)
思路:
容斥原理套DP。
假设我们已经求出了DP数组 \(f[S]\),表示有多少个 \(a\) 中的元素,满足 \(S\) 中的位都是1。
其中,\(a_{i,j}\) 表示 \(a_i\) 的第 \(j\) 位。
最终的答案就是
再来考虑 \(f\) 怎么求。
设 \(dp[i,S]\) 表示,\(S\) 的前 \(i\) 位放宽了限制,\(S\) 的后 \(i\) 位还没有放宽限制的元素个数。
所谓放宽限制就是指,如果 \(S\) 这一位是1,那么元素这一位必须是1;如果 \(S\) 这一位是0,那么元素这一位没有要求。
所谓没有放宽限制就是指,必须和 \(S\) 中的每一位都相同。
最终,\(f[S]=dp[0,S]\)。
TopCoder P13444 CountTables
题意:
找出满足以下条件的 \(n\times m\) 矩阵的个数:
- 矩阵中的每个元素都是在 \(1\sim c\) 之间。
- 矩阵中不存在完全相同的两行,不存在完全相同的两列。
思路:
先来考虑如果只限制不存在完全相同的两行,这题该怎么做。
我们发现,每一行的取值有 \(c^m\) 种,从中挑出 \(n\) 个,再考虑顺序。即 \(\dbinom{c^m}{n}\times n!\)。
再来考虑加上不存在完全相同的两列的限制。
设DP状态 \(f[i]\) 为满足条件的 \(n\times i\) 的矩阵个数。
则 \(f[i] = \dbinom{c^i}{n}\times n! - \sum\limits_{j = 1}^{i - 1}S(i,j)\times f[j]\)。
其中 \(S\) 是第二类 Stirling 数。
P4827 [国家集训队] Crash 的文明世界
题意:
给出一棵 \(n\) 个点的树,对于每个节点 \(i\),求
思路:
运用一个著名的性质:
其中,\(x^{\underline{k}}\) 表示 \(x\times(x-1)\times (x-2)\times\cdots\times (x-k+1)\)
所以原式可以被化简为
我们可以换根DP处理 \(\sum\limits_{1\leq x\leq n}^{x\neq i}\dbinom{dist(x, i)}{p}\)。
CF1278F Cards
题意:
有 \(n\) 个独立的随机变量 \(x_i\),每个都有 \(P\) 的概率为1,有 \(1-P\) 的概率为0。计算 \(E\left(\left(\sum\limits_{i=1}^nx_i\right)^K\right)\)。
思路:
又是一道推式子题,还是得用到上一道题的性质。
考虑枚举1的个数。
数学就这么神奇!
P3349 [ZJOI2016]小星星
题意:
给出一个 \(n\) 个节点的树 \(T\) 和 \(n\) 个节点的无向图 \(G\),求点的映射的数量,使得树是图的子图。\(n \leq 17\)。
思路:
这题的标算非常精妙。
首先考虑一个暴力。
设DP状态 \(f[i, j, s]\) 表示 \(T\) 中的节点 \(i\) 被映射到 \(G\) 中的节点 \(j\),且 \(G\) 中 \(s\) 这些点已经被映射过的方案数。做一遍树形DP。转移时枚举子集转移即可。复杂度 \(O(3^n\times n^3)\),不足以通过本题。
于是我们放弃像 \(s\) 这样的精确的对应关系,转而把目光投在那些模糊的、不能准确描述的、可能有重复的状态设计上。
具体来说,我们在外层循环一个 \(s\),然后设 \(f[i,j]\) 表示 \(T\) 中的节点 \(i\) 被映射到 \(G\) 中的节点 \(j\) 上的方案数。对于 \(i\) 的一个儿子 \(v\) 以及它的映射 \(t\),转移的时候只需要保证 \(i\) 和 \(t\) 都在 \(s\) 中,且 \(G\) 中有 \((t,j)\) 这条边即可。
细想一下,这玩意绝对是错的。因为我们在转移的时候无法保证 \(i\) 的各个儿子所映射的节点是不同的。
所以,在外层循环结束后,我们开始容斥。
考虑如果映射中至少有一个点重复,那么 \(|s|\) 就会等于 \(n-1\)。类似地,如果映射中至少有 \(\alpha\) 个点重复,那么 \(|s|\) 就会等于 \(n-\alpha\)。
最终的答案就是 \(\sum\limits_s (-1)^{n-|s|} g(s)\)。其中,\(g(s)=\sum\limits_j f[1,j]\)。