[JSOI2018] 潜入行动
题目描述
外星人又双叒叕要攻打地球了,外星母舰已经向地球航行!这一次,JYY
已经联系好了黄金舰队,打算联合所有 JSOIer
抵御外星人的进攻。
在黄金舰队就位之前,JYY
打算事先了解外星人的进攻计划。现在,携带了监听设备的特工已经秘密潜入了外星人的母舰,准备对外星人的通信实施监听。
外星人的母舰可以看成是一棵 \(n\) 个节点、 \(n-1\) 条边的无向树,树上的节点用 \(1,2,\cdots,n\) 编号。JYY
的特工已经装备了隐形模块,可以在外星人母舰中不受限制地活动,可以神不知鬼不觉地在节点上安装监听设备。
如果在节点 \(u\) 上安装监听设备,则 JYY
能够监听与 \(u\) 直接相邻所有的节点的通信。换言之,如果在节点 \(u\) 安装监听设备,则对于树中每一条边 \((u,v)\) ,节点 \(v\) 都会被监听。特别注意放置在节点 \(u\) 的监听设备并不监听 \(u\) 本身的通信,这是 JYY
特别为了防止外星人察觉部署的战术。
JYY
的特工一共携带了 \(k\) 个监听设备,现在 JYY
想知道,有多少种不同的放置监听设备的方法,能够使得母舰上所有节点的通信都被监听?为了避免浪费,每个节点至多只能安装一个监听设备,且监听设备必须被用完。
code
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
int x = 0; char c = getchar();
while (! isdigit(c)) c = getchar();
while (isdigit(c))
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x;
}
const int mod = 1e9 + 7;
const int Maxn = 1e5 + 7;
vector<int> g[Maxn];
int n, k, dp[Maxn][101][4], tmp[101][4];
int siz[Maxn];
/*
* 令f[i][j][0~3]为以i为根节点的子树内,放了j个设备;
* 0表示为本身没放,当前节点没有覆盖;
* 1表示为本身放,当前节点没有覆盖;
* 2表示为本身没放,当前节点有覆盖;
* 3表示为本身放,当前节点有覆盖的方案数。
*
* f[u][i + j][0] = f[u][i][0] * f[v][j][2]
* f[u][i + j][1] = f[u][i][1] * (f[v][j][0] + f[v][j][2])
* f[u][i + j][2] = f[u][i][2] * (f[v][j][2] + f[v][j][3]) + f[u][i][0] * f[v][j][3]
* f[u][i + j][3] = f[u][i][1] * (f[v][j][1] + f[v][j][3]) + f[u][i][3] * f[v][j][0~3]
*/
void dfs(int u, int fa)
{
siz[u] = 1;
dp[u][0][0] = dp[u][1][1] = 1;
for (int v : g[u]) if (v != fa)
{
dfs(v, u);
for (int i = 0; i <= k; i ++ )
for (int j = 0; j <= 3; j ++ )
tmp[i][j] = 0;
for (int i = 0; i <= min(siz[u], k); i ++ )
for (int j = 0; j <= min(siz[v], k - i); j ++ )
{
tmp[i + j][0] = (1ll * dp[u][i][0] * dp[v][j][2] %mod + tmp[i + j][0]) %mod;
tmp[i + j][1] = (1ll * dp[u][i][1] * (1ll * dp[v][j][0] + 1ll * dp[v][j][2]) %mod + tmp[i + j][1]) %mod;
tmp[i + j][2] = (1ll * dp[u][i][2] * (1ll * dp[v][j][2] + 1ll * dp[v][j][3]) %mod + tmp[i + j][2]) %mod;
tmp[i + j][2] = (1ll * dp[u][i][0] * dp[v][j][3] %mod + tmp[i + j][2]) %mod;
tmp[i + j][3] = (1ll * dp[u][i][3] * (1ll * dp[v][j][0] + 1ll * dp[v][j][1] + 1ll * dp[v][j][2] + dp[v][j][3]) %mod + tmp[i + j][3]) %mod;
tmp[i + j][3] = (1ll * dp[u][i][1] * (1ll * dp[v][j][1] + dp[v][j][3]) %mod + tmp[i + j][3]) %mod;
}
siz[u] += siz[v];
for (int i = 0; i <= k; i ++ )
for (int j = 0; j <= 3; j ++ )
dp[u][i][j] = tmp[i][j];
}
}
int main()
{
n = read(); k = read();
for (int i = 1, u, v; i < n; i ++ )
{
u = read(), v = read();
g[u].push_back(v); g[v].push_back(u);
}
dfs(1, 0);
printf("%lld", (dp[1][k][2] + dp[1][k][3]) %mod);
return 0;
}