CF1551F Equidistant Vertices 题解
题意:给 个点的树和 ,边无权。问有多少种方案,选出 个点且 个点中两两距离相等。对 取模。,多测。
特判 时,输出 。
考虑 ,容易发现对于每个选出的点集 ,一定存在且仅存在一个点 ,使得整棵树以 为根时,点集中的点在 的不同儿子的子树中,且深度都相同。换句话说就是这个点集有一个中点。
考虑枚举这个点,这个的复杂度为 。然后处理出每个儿子的子树中每个深度的点数。枚举相同的深度 。考虑 DP,设 表示处理了前 个儿子,选了 个点的方案数。则 , 表示以 这个儿子为根的子树中深度为 的点数。
乍一看是 的,其实仔细分析是 的,不过证明略过,因为这个 看起来就跑不满。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <map>
using namespace std;
const int N = 105;
constexpr long long MOD = static_cast<long long>(1e9 + 7);
int t, n, k;
vector<int> G[N];
long long dp[N][N];
int cnt[N][N];
int maxd = 0;
int nowp = 0;
void dfs(int u, int fa, int d)
{
maxd = max(maxd, d);
cnt[nowp][d]++;
for (auto& j : G[u])
{
if (j == fa) continue;
dfs(j, u, d + 1);
}
}
int idx, son[N];
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> t;
while (t--)
{
cin >> n >> k;
for (int i = 1; i <= n; i++) G[i].clear(), G[i].shrink_to_fit();
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
G[u].emplace_back(v);
G[v].emplace_back(u);
}
if (k == 2)
{
cout << n * (n - 1) / 2 << "\n";
continue;
}
long long ans = 0LL;
for (int i = 1; i <= n; i++)
{
maxd = 0;
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++) cnt[j][k] = 0;
}
idx = 0;
for (auto& j : G[i])
{
nowp = j;
dfs(j, i, 2);
son[++idx] = j;
}
for (int d = 2; d <= maxd; d++)
{
int lst = 0;
for (int j = 0; j <= idx; j++)
{
for (int p = 0; p <= k; p++) dp[j][p] = 0;
}
dp[0][0] = 1;
for (int p = 1; p <= idx; p++)
{
if (!cnt[son[p]][d])
{
continue;
}
for (int c = 0; c <= k; c++)
{
dp[p][c] = (dp[lst][c] + (!c ? 0LL : dp[lst][c - 1] * cnt[son[p]][d] % MOD)) % MOD;
}
lst = p;
}
ans = (ans + dp[lst][k]) % MOD;
}
}
cout << ans << "\n";
}
return 0;
}

浙公网安备 33010602011771号