HDU 5905 Black White Tree(树型DP)
题目链接 Black White Tree
树型DP,设$f[i][j]$为以$i$为根的子树中大小为$j$的连通块中可以包含的最小黑点数目。
$g[i][j]$为以$i$为根的子树中大小为$j$的连通块中可以包含的最大黑点数目。
$F[i]$为大小为$i$的连通块中可以包含的最小黑点数目
$G[i]$为大小为$j$的连通块中可以包含的最大黑点数目
做一遍树上DP即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 2020; int n; char s[N]; int a[N]; int T; vector <int> v[N]; LL ans = 0; int F[N << 1], G[N << 1]; int f[N][N], g[N][N]; int sz[N]; void dfs(int x, int fa){ sz[x] = 1; if (a[x]) f[x][1] = g[x][1] = 1; else f[x][1] = g[x][1] = 0; for (auto u : v[x]){ if (u == fa) continue; dfs(u, x); dec(i, sz[x], 1){ rep(j, 1, sz[u]){ f[x][i + j] = min(f[x][i + j], f[x][i] + f[u][j]); g[x][i + j] = max(g[x][i + j], g[x][i] + g[u][j]); } } sz[x] += sz[u]; } rep(i, 1, sz[x]){ F[i] = min(F[i], f[x][i]); G[i] = max(G[i], g[x][i]); } } inline int query(int x, int y){ return (F[x + y] <= y && G[x + y] >= y) ? 1 : 0; } int main(){ scanf("%d", &T); while (T--){ scanf("%d", &n); scanf("%s", s + 1); rep(i, 1, n) a[i] = (int)s[i] - 48; rep(i, 0, n) v[i].clear(); rep(i, 0, n) rep(j, 0, n){ f[i][j] = 1 << 27; g[i][j] = 0; } rep(i, 0, n << 1) F[i] = 1 << 27, G[i] = 0; rep(i, 1, n - 1){ int x, y; scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } ans = 0; dfs(1, 0); rep(i, 0, n) rep(j, 0, n) ans += (LL)(i + 1) * (j + 1) * query(i, j); printf("%lld\n", ans + 1); } return 0; }