题目大意:
给你一棵n个节点的带标号无根树。每次,你可以选择一个度数为1的节点并将它从树上移除。问总共有多少种不同的方式能将这棵树删到只剩 1 个点。两种方式不同当且仅当至少有一步被删除的节点不同。
方案数对998244353取模。
n≤100000
分析:
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
#define N 100005
using namespace std;
const int mo = 998244353;
struct Node {
int To, nxt;
}e[N*2];
int inv[N], jcv[N], jc[N], ls[N], sz[N], n, cnt, sum, ans = 1;
void Addedge(int u, int v)
{
e[++cnt].To = v, e[cnt].nxt = ls[u], ls[u] = cnt;
e[++cnt].To = u, e[cnt].nxt = ls[v], ls[v] = cnt;
}
void dfs(int x, int fa)
{
sz[x] = 1;
for (int i = ls[x]; i; i = e[i].nxt)
{
if (e[i].To == fa) continue;
int y = e[i].To;
if (y != fa)
{
dfs(y, x);
sz[x] += sz[y];
ans = 1LL * ans * jcv[sz[y]] % mo;
}
}
ans = 1LL * ans * jc[sz[x] - 1] % mo;
}
void solve(int x, int fa, int num)
{
sum = (sum + num) % mo;
for (int i = ls[x]; i; i = e[i].nxt)
{
int y = e[i].To;
if (y == fa) continue;
solve(y, x, 1LL * num * inv[n - sz[y]] % mo * sz[y] % mo);
}
}
int main()
{
scanf("%d", &n);
ans = 1, sum = 0;
jc[0] = jc[1] = 1;
jcv[0] = jcv[1] = 1;
inv[1] = 1;
for (int i = 2; i <= n; i++)
{
jc[i] = 1LL * jc[i - 1] * i % mo;
inv[i] = 1LL * (mo - mo / i) * inv[mo % i] % mo;
jcv[i] = 1LL * jcv[i - 1] * inv[i] % mo;
}
for (int i = 1; i < n; i++)
{
int x, y; scanf("%d %d", &x, &y);
Addedge(x, y);
}
dfs(1, -1);
solve(1, -1, ans);
printf("%d\n", sum);
return 0;
}