以下题目都是本专题的经典例题。如不特别说明,则题目来源为洛谷。
P3197 [HNOI2008]越狱
题意:
(n) 个格子,(m) 种颜色,求至少有两个相邻格子颜色相同的方案数。
思路:
补集转换,求不存在任何两个相邻格子颜色相同的方案数。乘法原理。
答案是
P6184 [USACO08OCT]Building A Fence G
题意:
长为 (n) 的木板,需要把木板切成四块,使得这四块可以围成面积不为零的四边形。求方案数。(nleq 2500)。
思路:
原题当然很简单,我们考虑 (O(n)) 怎么做。
考虑从 (n) 个物品中插入3个隔板。总方案数为 (dbinom{n - 1}{3})。
减去不合法的方案数,即至少有一块长度大于等于 (leftlceildfrac{n}{2} ight ceil)。考虑枚举最长板的长度,再在剩下的长度中隔板法。注意最后乘上4。
最终答案
BZOJ3907 网格
题意:
从笛卡尔坐标系 ((0,0)) 走到 ((n,m)),中途保证 (xgeq y) 的方案数。
思路:
简单卡特兰数扩展。
P4071 [SDOI2016]排列计数
题意:
求有多少个 (1sim 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;
}
求有多少个 (1sim n) 的排列,使得它求出来的最大值不是 (n)。
思路:
先DP。(f[i]) 表示有多少个 (1sim i) 的排列满足函数运行到最后还没有退出。
前缀和优化。
BZOJ4403 序列统计
题意:
长度在 (1sim n) 期间,元素大小在 (Lsim R) 之间的单调不降序列的数量。
思路:
设 (m = R - L + 1)。
插板法,考虑枚举长度 (i),一共有 (i) 个物品,(m - 1) 个插板。当然插板可以为空。再用上指标求和公式。
P6669 [清华集训2016] 组合数问题
题意:
对于给定的 (n,m,K),有多少个 (0leq i leq n,0leq jleq 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 imes m) 的矩阵上放 (K) 个人。满足:
- 四个边上必须有人。
- 每个格子上至多放一个人。
- 每个人都有位置。
求方案数。
思路:
设 (A_1) 代表最上边没人的方案的集合,(A_2) 代表最下边没人的方案的集合,(A_3) 代表最左边没人的方案的集合,(A_4) 代表最右边没人的方案的集合。
求 (|overline{A_1}capoverline{A_2}capoverline{A_3}capoverline{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 imes m) 矩阵的个数:
- 矩阵中的每个元素都是在 (1sim c) 之间。
- 矩阵中不存在完全相同的两行,不存在完全相同的两列。
思路:
先来考虑如果只限制不存在完全相同的两行,这题该怎么做。
我们发现,每一行的取值有 (c^m) 种,从中挑出 (n) 个,再考虑顺序。即 (dbinom{c^m}{n} imes n!)。
再来考虑加上不存在完全相同的两列的限制。
设DP状态 (f[i]) 为满足条件的 (n imes i) 的矩阵个数。
则 (f[i] = dbinom{c^i}{n} imes n! - sumlimits_{j = 1}^{i - 1}S(i,j) imes f[j])。
其中 (S) 是第二类 Stirling 数。
P4827 [国家集训队] Crash 的文明世界
题意:
给出一棵 (n) 个点的树,对于每个节点 (i),求
思路:
运用一个著名的性质:
其中,(x^{underline{k}}) 表示 (x imes(x-1) imes (x-2) imescdots imes (x-k+1))
所以原式可以被化简为
我们可以换根DP处理 (sumlimits_{1leq xleq n}^{x eq i}dbinom{dist(x, i)}{p})。
CF1278F Cards
题意:
有 (n) 个独立的随机变量 (x_i),每个都有 (P) 的概率为1,有 (1-P) 的概率为0。计算 (Eleft(left(sumlimits_{i=1}^nx_i ight)^K ight))。
思路:
又是一道推式子题,还是得用到上一道题的性质。
考虑枚举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 imes 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)。
最终的答案就是 (sumlimits_s (-1)^{n-|s|} g(s))。其中,(g(s)=sumlimits_j f[1,j])。