CF1551F Equidistant Vertices 题解

题意:给 nn 个点的树和 kk,边无权。问有多少种方案,选出 kk 个点且 kk 个点中两两距离相等。对 109+710^9+7 取模。2kn1002 \leq k \leq n \leq 100,多测。

特判 k=2k=2 时,输出 (n2)\dbinom{n}{2}

考虑 k>2k > 2,容易发现对于每个选出的点集 SS,一定存在且仅存在一个点 uu,使得整棵树以 uu 为根时,点集中的点在 uu 的不同儿子的子树中,且深度都相同。换句话说就是这个点集有一个中点。

考虑枚举这个点,这个的复杂度为 O(n)O(n)。然后处理出每个儿子的子树中每个深度的点数。枚举相同的深度 dd。考虑 DP,设 fi,jf_{i,j} 表示处理了前 ii 个儿子,选了 jj 个点的方案数。则 fi,j=fi1,j+fi1,j1×cnti,df_{i,j} = f_{i-1,j} + f_{i-1,j-1} \times cnt_{i,d}cnti,dcnt_{i,d} 表示以 ii 这个儿子为根的子树中深度为 dd 的点数。

乍一看是 O(n4)O(n^4) 的,其实仔细分析是 O(n2k)O(n^2k) 的,不过证明略过,因为这个 O(n4)O(n^4) 看起来就跑不满。

#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;
}
posted @   HappyBobb  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示