潜入行动
题目背景:
5.14 模拟 JSOI2018D1T1
分析:树型DP
比较显然的树型DP,定义dp[i][j][0/1][0/1]表示,以i为根的子树,子树内有j个监听设备,节点i是否被监听,节点i是否有监听设备,每次合并子树就可以了,注意for循环不要每次到k,循环到min(size[cur], k)就可以了。详见代码,复杂度O(nk2),听说是O(nk)的,但是我是证不了的······(反正跑得快就好。)
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
inline char read() {
static const int IN_LEN = 1024 * 1024;
static char buf[IN_LEN], *s, *t;
if (s == t) {
t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
if (s == t) return -1;
}
return *s++;
}
///*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return ;
if (c == '-') iosig = true;
}
for (x = 0; isdigit(c); c = read())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
*oh++ = c;
}
template<class T>
inline void W(T x) {
static int buf[30], cnt;
if (x == 0) write_char('0');
else {
if (x < 0) write_char('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) write_char(buf[cnt--]);
}
}
inline void flush() {
for (int i = 0; i <= 10; ++i) std::cout << obuf[i];
std::cout << '\n';
fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
/*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
if (c == '-') iosig = true;
for (x = 0; isdigit(c); c = getchar())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int MAXN = 100000 + 5;
const int MAXK = 100 + 5;
const int mod = 1000000000 + 7;
int n, k, x, y;
int dp[MAXN][MAXK][2][2];
int size[MAXN];
std::vector<int> edge[MAXN];
inline void add_edge(int x, int y) {
edge[x].push_back(y), edge[y].push_back(x);
}
inline void read_in() {
R(n), R(k);
for (int i = 1; i < n; ++i) R(x), R(y), add_edge(x, y);
}
inline void add(int &x, int t) {
x += t, (x >= mod) ? (x -= mod) : (0);
}
inline void dfs(int cur, int fa) {
static int temp[MAXK][2][2];
size[cur] = 1, dp[cur][0][0][0] = dp[cur][1][0][1] = 1;
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p];
if (v == fa) continue ;
dfs(v, cur);
for (int i = 0, ie = std::min(size[cur] + size[v], k); i <= ie; ++i)
temp[i][0][0] = temp[i][0][1] = temp[i][1][0] = temp[i][1][1] = 0;
for (int i = 0, ie = std::min(size[cur], k); i <= ie; ++i)
for (int j = 0, je = std::min(size[v], k - i); j <= je; ++j) {
add(temp[i + j][0][0], (long long)dp[cur][i][0][0]
* dp[v][j][1][0] % mod);
add(temp[i + j][0][1], (long long)dp[cur][i][0][1]
* (dp[v][j][0][0] + dp[v][j][1][0]) % mod);
add(temp[i + j][1][0], ((long long)dp[cur][i][0][0]
* dp[v][j][1][1] + (long long)dp[cur][i][1][0]
* (dp[v][j][1][0] + dp[v][j][1][1])) % mod);
long long x = (long long)dp[v][j][0][0] + dp[v][j][0][1]
+ dp[v][j][1][0] + dp[v][j][1][1];
add(temp[i + j][1][1], ((long long)dp[cur][i][0][1]
* (dp[v][j][0][1] + dp[v][j][1][1])
+ x * dp[cur][i][1][1]) % mod);
}
// std::cout << cur << '\n';
for (int i = 0, ie = std::min(size[cur] + size[v], k); i <= ie; ++i) {
dp[cur][i][0][0] = temp[i][0][0], dp[cur][i][0][1] = temp[i][0][1];
dp[cur][i][1][0] = temp[i][1][0], dp[cur][i][1][1] = temp[i][1][1];
}
size[cur] += size[v];
}
}
int main() {
//freopen("action.in", "r", stdin);
//freopen("action.out", "w", stdout);
read_in();
dfs(1, 0);
long long ans = 0;
ans = dp[1][k][1][0] + dp[1][k][1][1];
std::cout << ans % mod;
return 0;
}