注意到這個問題具有最優子結構性,考慮樹上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;
}