JSOI2018 潜入行动
好久没有写单道题的题解了。之所以想写一写这道题,是因为它差不多是树形dp的模板的有一定思维难度的题了,有一定的纪念价值。
那么先看题目。
数据规模:

思路:既然题目给出了显式树,那么这道题很显然是道树形dp。既然是树形dp,我们就来列一下状态:
设f[u][j][k][l]表示以u节点为根的子树,安装j个监听器,且u节点放置监听器状态为k(0/1),被子节点监听状态为l(0/1),且除u外整棵子树均被监听。
那么就是一个树包,分别讨论f[u][j][0][0],f[u][j][0][1],f[u][j][1][0],f[u][j][1][1]的转移即可。
对于u的一个子节点v,分配t个监听器,于是有以下转移:
情况一:u节点既没有被监视,又没有放置装置,那么它的子节点不能放置装置,且必须被监视,f[u][j][0][0] += f[u][j - t][0][0] * f[v][t][0][1]
情况二:u节点没有被监视,但安放了装置,那么它的子节点不能放置装置,但是否被监视均可,f[u][j][1][0] += f[u][j - t][1][0] * (f[v][t][0][0] + f[v][t][0][1])
接下来两种情况比较复杂,
情况三:u节点被监视(父节点或子节点),但没有安放装置,
又分两种情况:
1.若u节点被子节点监视,则子节点必须安放装置,且必须被监视,f[u][j][0][1] += f[u][j - t][0][0] * f[v][t][1][1]
2.若u节点被父节点监视,则子节点是否安放装置均可,但必须被监视,f[u][j][0][1] += f[u][j - t][0][1] * (f[v][t][0][1] + f[v][t][1][1])
情况四:u节点被监视(父节点或子节点),且安放了装置
分两种情况:
1.若u节点被子节点监视,则子节点必须安放装置,是否被监视均可,f[u][j][1][1] += f[u][j - t][1][0] * (f[v][t][1][0] + f[v][t][1][1])
2.若u节点被父节点监视,则子节点无论是否安放装置,是否被监视均可,f[u][j][1][1] += f[u][j - t][1][1] * (f[v][t][0][0] + f[v][t][0][1] + f[v][t][1][0] + f[v][t][1][1])
以上就是所有转移了。
代码如下(转移采用刷表法,类似):
#include <bits/stdc++.h> using namespace std; const int mod = 1e9 + 7; int f[100005][105][2][2], g[105][2][2]; struct node { int to, nxt; }e[200005]; int head[100005], cnt[100005], tot, n, k; inline void add_e(int u, int v) {e[++tot].to = v; e[tot].nxt = head[u]; head[u] = tot;} void dp(int u, int fa) { f[u][0][0][0] = f[u][1][1][0] = 1; cnt[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa) continue; dp(v, u); for (int j = 0; j <= min(cnt[u], k); j++) memcpy(g[j], f[u][j], sizeof f[u][j]), memset(f[u][j], 0, sizeof f[u][j]); for (int j = min(cnt[u], k); ~j; j--) { for (int t = 0; t <= min(cnt[v], k - j); t++) { f[u][j + t][0][0] = (f[u][j + t][0][0] + (1ll * g[j][0][0] * f[v][t][0][1] % mod)) % mod; f[u][j + t][1][0] = (f[u][j + t][1][0] + (1ll * g[j][1][0] * ((f[v][t][0][0] + f[v][t][0][1]) % mod)) % mod) % mod; f[u][j + t][0][1] = (f[u][j + t][0][1] + (1ll * g[j][0][1] * ((f[v][t][0][1] + f[v][t][1][1]) % mod)) % mod) % mod; f[u][j + t][0][1] = (f[u][j + t][0][1] + (1ll * g[j][0][0] * f[v][t][1][1]) % mod) % mod; f[u][j + t][1][1] = (f[u][j + t][1][1] + (1ll * g[j][1][0] * ((f[v][t][1][0] + f[v][t][1][1]) % mod)) % mod) % mod; f[u][j + t][1][1] = (f[u][j + t][1][1] + (1ll * g[j][1][1] * (((f[v][t][0][0] + f[v][t][0][1]) % mod + (f[v][t][1][0] + f[v][t][1][1]) % mod) % mod)) % mod) % mod; } } cnt[u] += cnt[v]; } } int main() { scanf("%d%d", &n, &k); for (int i = 1, x, y; i < n; i++) { scanf("%d%d", &x, &y); add_e(x, y); add_e(y, x); } dp(1, 0); printf("%d", (f[1][k][0][1] + f[1][k][1][1]) % mod); }

浙公网安备 33010602011771号