SP666 VOCV - Con-Junctions 題解

EternalEpic發表於2024-08-25

注意到這個問題具有最優子結構性,考慮樹上dp。記 $dp[i][0/1]$ 表示 i 號節點不放燈或放燈的最小值,$s[i][0/1]$ 為對應的方案數。

那麼我們可以進行如下轉移: $dp[u][0] = \sum_{u->v} dp[v][1]$ $dp[u][1] = \sum_{u->v} \min(dp[v][0], dp[v][1])$

在更新對應的dp陣列時,我們用乘法原理同步更新s陣列即可。

const int N = 100015, mod = 10007;
int T, n; vector <int> G[N];

int dp[N][2], s[N][2];
inline void dfs(int u, int f) {
	dp[u][1] = 1;
	for (auto v : G[u]) {
		if (v == f) continue;
		dfs(v, u);
		if (dp[v][1] > dp[v][0]) dp[u][1] += dp[v][0], s[u][1] = s[u][1] * s[v][0] % mod;
		else if (dp[v][1] < dp[v][0]) dp[u][1] += dp[v][1], s[u][1] = s[u][1] * s[v][1] % mod;
		else dp[u][1] += dp[v][0], s[u][1] = s[u][1] * (s[v][0] + s[v][1]) % mod;
		dp[u][0] += dp[v][1]; s[u][0] = s[u][0] * s[v][1] % mod;
	}
}

signed main(void) {
	for (read(T); T; T--) {
		read(n);
		for (int i = 1; i <= n; i++) G[i].clear(), dp[i][0] = dp[i][1] = 0, s[i][0] = s[i][1] = 1;
		for (int i = 1, u, v; i < n; i++) read(u), read(v), G[u].push_back(v), G[v].push_back(u);
		dfs(1, 0);
		if (dp[1][1] > dp[1][0]) writeln(dp[1][0], ' '), writeln(s[1][0]);
		else if (dp[1][1] < dp[1][0]) writeln(dp[1][1], ' '), writeln(s[1][1]);
		else writeln(dp[1][0], ' '), writeln((s[1][0] + s[1][1]) % mod);
	}
    return 0;
}