AtCoder Beginner Contest 207 F Tree Patrolling
简单树形 dp。
设 \(f_{u,i,p=0/1,q=0/1}\) 为 \(u\) 的子树中被覆盖点数为 \(i\),\(u\) 有没有被覆盖,\(u\) 有没有被选。
转移树形背包合并即可,需要分类讨论。要注意如果 \(u\) 没被覆盖,\(v\) 选了,或者 \(u\) 选了,\(v\) 没被覆盖,被覆盖点数要 \(+1\)。
式子较复杂,具体见代码。
code
// Problem: F - Tree Patrolling
// Contest: AtCoder - AtCoder Beginner Contest 207
// URL: https://atcoder.jp/contests/abc207/tasks/abc207_f
// Memory Limit: 1024 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 2020;
const ll mod = 1000000007;
ll n, f[maxn][maxn][2][2], sz[maxn], head[maxn], len, g[maxn][2], h[maxn][maxn][2];
struct edge {
int to, next;
} edges[maxn << 1];
inline void add_edge(int u, int v) {
edges[++len].to = v;
edges[len].next = head[u];
head[u] = len;
}
void dfs(int u, int fa) {
f[u][0][0][0] = f[u][1][1][1] = 1;
sz[u] = 1;
for (int i = head[u]; i; i = edges[i].next) {
int v = edges[i].to;
if (v == fa) {
continue;
}
dfs(v, u);
for (int j = 0; j <= sz[u]; ++j) {
g[j][0] = f[u][j][0][0];
g[j][1] = f[u][j][1][0];
f[u][j][0][0] = f[u][j][1][0] = 0;
}
for (int j = 0; j <= sz[u]; ++j) {
for (int k = 0; k <= sz[v]; ++k) {
for (int x = 0; x <= 1; ++x) {
for (int y = 0; y <= 1; ++y) {
if (!x && y) {
f[u][j + k][0][0] = (f[u][j + k][0][0] + g[j][0] * f[v][k][1][0] % mod) % mod;
f[u][j + k + 1][1][0] = (f[u][j + k + 1][1][0] + g[j][0] * f[v][k][1][1] % mod) % mod;
} else {
f[u][j + k][x | y][0] = (f[u][j + k][x | y][0] + g[j][x] * h[v][k][y] % mod) % mod;
}
}
}
}
}
for (int j = 0; j <= sz[u]; ++j) {
g[j][0] = f[u][j][0][1];
g[j][1] = f[u][j][1][1];
f[u][j][0][1] = f[u][j][1][1] = 0;
}
for (int j = 0; j <= sz[u]; ++j) {
for (int k = 0; k <= sz[v]; ++k) {
for (int x = 0; x <= 1; ++x) {
f[u][j + k + (x ^ 1)][1][1] = (f[u][j + k + (x ^ 1)][1][1] + g[j][1] * h[v][k][x] % mod) % mod;
}
}
}
sz[u] += sz[v];
}
for (int i = 0; i <= sz[u]; ++i) {
h[u][i][0] = (f[u][i][0][0] + f[u][i][0][1]) % mod;
h[u][i][1] = (f[u][i][1][0] + f[u][i][1][1]) % mod;
}
}
void solve() {
scanf("%lld", &n);
for (int i = 1, u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
dfs(1, -1);
for (int i = 0; i <= n; ++i) {
printf("%lld\n", (h[1][i][0] + h[1][i][1]) % mod);
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}