题解:P11363 [NOIP2024] 树的遍历
菊花图且
链:边的邻接关系同样构成链,所有只有一种生成树,答案为
考虑有多少种答案同时满足两个起始边的条件,令
正解:可以先以
容易发现中间点处无解。
于是我们可以考虑树上 DP。先进行容斥,令
贡献答案则是枚举两棵子树,或者当前点为起始点连向子树内某个点,是容易的。
最后答案应该乘以
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int mod = 1000000000 + 7;
constexpr int maxn = 100000 + 10;
i64 qp(i64 a, i64 b)
{
i64 c = 1;
for (; b; b>>=1, a=a*a%mod)
if (b & 1) c=c*a%mod;
return c;
}
i64 fac[maxn], inv[maxn];
vector<int> g[maxn];
i64 f[maxn];
int o[maxn];
i64 ans;
void dp(int u, int fa)
{
i64 s = 0, p = 0;
for (int v : g[u]) if (v != fa)
{
dp(v, u);
p = (p + s * f[v]) % mod;
s = (s + f[v]) % mod;
}
i64 c = g[u].size() == 1 ? 1 : inv[g[u].size() - 1] * fac[g[u].size() - 2] % mod;
ans = (ans - p * c % mod + mod) % mod;
if (o[u])
{
f[u] = mod - 1;
for (int v : g[u]) if (v != fa)
{
ans = (ans + f[v] * c % mod + mod) % mod;
}
}
else f[u] = s * c % mod;
}
int d[maxn];
void dfs(int u, int fa)
{
d[u] = d[fa] + 1;
for (int v : g[u]) if (v != fa) dfs(v, u);
}
int u[maxn], v[maxn];
void solve()
{
int n, k;
cin >> n >> k;
for (int i=1;i<=n;++i) g[i].clear();
memset(f, 0, sizeof(f));
memset(o, 0, sizeof(o));
for (int i=1;i<n;++i)
{
cin >> u[i] >> v[i];
g[u[i]].emplace_back(v[i]);
g[v[i]].emplace_back(u[i]);
}
dfs(1, 0);
for (int i=1;i<=k;++i)
{
int x;
cin >> x;
o[d[u[x]] < d[v[x]] ? v[x] : u[x]] = 1;
}
ans = k;
dp(1, 0);
for (int i=1;i<=n;++i) ans = ans * fac[g[i].size() - 1] % mod;
cout << ans << '\n';
}
int main()
{
fac[0] = 1;
for (int i=1;i<maxn;++i) fac[i] = fac[i - 1] * i % mod;
inv[maxn - 1] = qp(fac[maxn - 1], mod - 2);
for (int i=maxn-2;i>=0;--i) inv[i] = inv[i + 1] * (i + 1) % mod;
ios::sync_with_stdio(0);
cin.tie(0);
int c, t;
cin >> c >> t;
while (t--) solve();
return 0;
}