数数题(计数类 DP)做题记录
数数题(计数类 DP)做题记录
CF1657E Star MST
我们称张无向完全图是美丽的当且仅当:所有和 \(1\) 相连的边的边权之和等于这张完全图的最小生成树的边权之和。
完全图点数为 \(n\),边权 \(\in[1,k]\),\(1\le n,k\le 250\)。
发现所有和 \(1\) 相连的边边权之和等于 MST 的边权之和,即限制这张图的 MST 就是以 \(1\) 为中心的“星星”形状。
所以任意两个点之间的边权一定大于等于他们与 \(1\) 相连的边的边权的最大值。
那么设 \(dp(i,j)\) 表示连了 \(\le i\) 的边权,选择了除了 \(1\) 之外 \(j\) 个点的方案数。
那么枚举状态,将转移表示把边权为 \(i\) 边新加进去,可以得到转移方程:
总时间复杂度 \(\mathcal{O(n^3)}\)(假设 \(n,k\) 同阶)。
P8096 [USACO22JAN] Drought G
Farmer John 的 \(n(n\le 100)\) 头奶牛站成一排,每一个都有一个饥饿值 \(h_i\),Farmer John 可以每次选择相邻的两头奶牛使她们的饥饿值同时 \(-1\)。
Farmer John 想让他的所有奶牛都有相同的饥饿值,尽管他不知道每头奶牛具体的饥饿值,只知道她们每一头饥饿值的上限 \(H_i(H_i\le 1000)\),使得 \(h_i\le H_i\)。
请计算出所有满足 Farmer John 的要求的 \(n\) 元组 \([h_1,h_2,\cdots,h_n]\) 数量对 \(10^9+7\) 取模的结果。
假设最终都到达的饥饿值为 \(k\),设 \(dp_{i,j}\) 表示前 \(i-1\) 头牛都达到了要求,第 \(i\) 头牛的饥饿值为 \(j\) 的方案数。
那么因为需要让 \(i\) 牛也变成 \(k\),可以列出转移方程:
上面的方程可以用前缀和优化实现 \(O(1)\) 转移。
那么最终答案就是 \(dp_{n,k}\)。
由于我们发现如果 \(n\) 是偶数,可以通过 \(\dfrac{n}{2}\) 次操作使所有饥饿值 \(-1\),所以如果 \(n\) 为偶数只用枚举一个 \(k\) 即可。
CF724F Uniformly Branched Trees
给定三个数 \(n,d,mod\),求有多少种 \(n\) 个点的不同构的树满足:除了度数为 \(1\) 的结点外,其余结点的度数均为 \(d\) 。答案对质数 \(mod\) 取模。
\(1\le n\le 10^3,2\le d\le 10,10^8\le mod\le 10^9\)。
听 jpj 说需要无标号无根树计数的一个技巧:
\(\bigstar\texttt{Trick}\):在计算无标号无根树的时候,为了去重,我们用有根树数量减去根不是重心的数量。
-
如果树的大小 \(n\) 是奇数,根节点不是重心,那么一定有一棵子树大小大于 \(\left\lfloor\dfrac{n}{2}\right\rfloor\)。如果将最大的子树看做另外一棵树,这棵树的方案数是 \(f_k\times f_{n-k}\),答案为:
\[f_{n}-\sum_{k=\lfloor\frac{n}{2}\rfloor+1}^{n-1}f_k\times f_{n-k} \] -
如果 \(n\) 是偶数,可能存在两个重心,可能出现的上面式子中 \(2k=n\) 的情况会再一次重复,需要额外减去 \(\dbinom{f_{\frac{n}{2}}}{2}\)。
回到这道题,首先我们推式子,设 \(k\) 为度数为 \(d\) 的点的个数,则容易推出 \(k=\dfrac{n-2}{d-1}\)。
收到上面的启发,先考虑带有标号的计数。
设 \(dp_{i,j,k}\) 表示以 \(j\) 为根的树中,除了 \(j\) 以外度数为 \(d\) 的点的个数为 \(i\),根的度数为 \(k\)。
考虑每次加的时候都是将一个子树合并到另一棵树的根下,保证除了根以外的每个点的度数都是合法的。
转移呢?这不至少 \(\mathcal{O(n^4)}\)???不会了捏
\(\bigstar\texttt{Hint}\):对于无根树而言,能够确定的一个点就是重心,由于需要用重心去重,可以设 \(dp_{i,j,k}\) 表示节点数为 \(i\),有 \(j\) 课子树,子树大小都不超过 \(k\) 的有根树数量。
接下来分类讨论(都是以重心作为根):
- 如果新树的子树大小都 \(<k\),那么直接从 \(dp_{i,j,k-1}\) 转移过来。
- 否则至少有一颗子树大小等于 \(k\),枚举等于 \(k\) 的子树的个数 \(t\):
(不得不说这个状态太牛逼了),子树大小等于 \(k\) 的子树方案数是 \(dp_{k,d-1,k-1}\),接下来我们需要做的就是从中选出 \(t\) 种子树(可以相同,部分顺序),这个方案数是 \(\dbinom{dp_{k,d-1,k-1}+t-1}{t}\)。
那么以上就是只有单重心的情况,答案就是 \(dp_{n,d,\lfloor\frac{n}{2}\rfloor}\)。
如果是双重心的情况,一定是一条边连接着两个相同的子树,即从 \(dp_{\frac{n}{2},d-1,\frac{n}{2}-1}\) 种方案中选出两个出来作为幸运儿就是重复的情况了。
所以双重心的答案就是 \(dp_{n,d,\frac{n}{2}}-\dbinom{dp_{\frac{n}{2},d-1,\frac{n}{2}-1}}{2}\)。
\(\bigstar\texttt{Question?}\) 转移的时候如果 \(k=1\),特判???
P3349 [ZJOI2016]小星星
给定一颗 \(n\) 个点的树,又给定一张 \(n\) 个点的图,需要将树中的 \(n\) 个点与图中的 \(n\) 个点一一对应,使得所有树中存在的边在图中能够找到与之对应的边。问对应方案数。
\(n\le 17\)。
当然是状压,但是怎么对应方案捏?
设 \(dp_{i,s}\) 表示在图中选择了前 \(i\) 个点,在树中选择点的集合是 \(s\) 的方案数。
这样选择一个点加入的时候就不知道以前的连边方案?显然假了。
\(\bigstar\texttt{Hint}\):为了避免不知道以前如何连边的情况,保持原来树的结构,即定 \(dp_{i,j,s}\) 表示在以 \(i\) 为根的子树中,\(i\) 对应图中的 \(j\),子树中的点已经对应了图中 \(s\) 的点的方案数。
这样可以暴力地实现 \(\mathcal{O(n^3\times 3^n)}\) 转移。
但是这样由于巨大的空间和时间复杂度只有 \(50\) 分,考虑更加优美的解法。
\(\bigstar\texttt{Hint}\):状态中为什么要记录 \(s\) 这一维?因为要让整棵树是 \(1-n\) 的排列。那么如果不记录会怎么样?编号会重合!重复怎么办?容斥!!!
用 \(2^n\) 枚举 \(\{1,2,\dots,n\}\) 的子集 \(T\),强制规定每个点的编号都属于 \(T\) 集合,容斥一下就好啦!。
P8273 [USACO22OPEN] Pair Programming G
还是不会
P4778 Counting swaps
咕咕咕