#734 (Div. 3) 1551 F. Equidistant Vertices(暴力枚举...)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#734 (Div. 3) 1551 F. Equidistant Vertices(暴力枚举...)相关的知识,希望对你有一定的参考价值。

LINK

比赛时没看题,发现是非常暴力的一题,嗯,反正这种写法非常暴力…

k = = 2 k==2 k==2时,显然答案是 n ∗ ( n − 1 ) 2 \\frac{n*(n-1)}{2} 2n(n1)

k > 2 k>2 k>2

由于任意两点间的距离都相等,必然存在一个中间点 r r r

满足 d i s ( a 1 , r ) = d i s ( a 2 , r ) = d i s ( a 3 , r ) . . . . dis(a_1,r)=dis(a_2,r)=dis(a_3,r).... dis(a1,r)=dis(a2,r)=dis(a3,r)....

于是我们枚举每个点作为中心点 r r r d f s dfs dfs

我们可以枚举 d i s ( a i , r ) dis(a_i,r) dis(ai,r)的距离为 w w w,也就是深度为 w w w

那么枚举 r r r的直接儿子 v 1 , v 2 . . . v s v_1,v_2...v_s v1,v2...vs,处理一个数组 z i [ i ] [ j ] zi[i][j] zi[i][j]表示 i i i子树中深度为 j j j的有多少

显然同属于 i i i子树中的点同时只能选一个,否则中心点 ( l c a ) (lca) (lca)就变成 i i i或者 i i i子树中的节点而不是 r r r

于是枚举深度 w w w后,就是从 z i [ v 1 ] [ w ] , z i [ v 2 ] [ w ] . . . z i [ v s ] [ w ] zi[v_1][w],zi[v_2][w]...zi[v_s][w] zi[v1][w],zi[v2][w]...zi[vs][w]中选出 k k k个的方案

这就变成了一个简单的 d p dp dp,定义 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i棵子树选 j j j棵的方案数

f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − 1 ] ∗ z i [ v i ] [ w ] f[i][j]=f[i-1][j]+f[i-1][j-1]*zi[v_i][w] f[i][j]=f[i1][j]+f[i1][j1]zi[vi][w]

累加答案即可

枚举中心点 r r r复杂度 O ( n ) O(n) O(n),枚举深度 O ( n ) O(n) O(n), D P DP DP部分 O ( n 2 ) O(n^2) O(n2)

总体复杂度 O ( n 4 O(n^4 O(n4,实际远远跑不满

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 109;
const int mod = 1e9+7;
vector<int>vec[maxn];
int deep[maxn],zi[maxn][maxn],n,k;
void dfs(int u,int father,int rt)
{
	deep[u] = deep[father]+1; zi[rt][deep[u]]++;
	for(auto v:vec[u] )
	{
		if( v==father )	continue;
		dfs(v,u,rt);
	}
}
int f[maxn][maxn],w[maxn];
void upd(int &x,int y){ x = (x+y)%mod; }
int DP()
{
	for(int i=1;i<=w[0];i++)
	for(int j=0;j<=i && j<=k;j++)
		f[i][j] = 0;	
	f[0][0] = 1;
	for(int i=1;i<=w[0];i++)
	for(int j=0;j<=i && j<=k;j++)
	{
		if( j )	upd( f[i][j],f[i-1][j-1]*w[i]%mod );
		upd( f[i][j],f[i-1][j] );
	}
	return f[w[0]][k];
}
signed main()
{
	int t; cin >> t;
	while( t-- )
	{
		cin >> n >> k;
		for(int i=1;i<n;i++)
		{
			int l,r; scanf("%lld%lld",&l,&r);
			vec[l].push_back( r );
			vec[r].push_back( l );
		}
		if( k==2 )	cout << n*(n-1)/2 << endl;
		else
		{
			int res = 0;
			for(int i=1;i<=n;i++)
			{
				deep[i] = 0;
				for(auto v:vec[i] )	dfs(v,i,v);
				for(int j=1;j<=n;j++)//枚举深度
				{
					w[0] = 0;
					for(auto v:vec[i] )	w[++w[0]] = zi[v][j];
					res = ( res+DP() )%mod;
				}
				for(auto v:vec[i] )
				for(int j=1;j<=n;j++)	zi[v][j] = 0;			
			}
			cout << res << endl;
		}
		for(int i=1;i<=n;i++)	vec[i].clear();
	}
}

以上是关于#734 (Div. 3) 1551 F. Equidistant Vertices(暴力枚举...)的主要内容,如果未能解决你的问题,请参考以下文章

#734 (Div. 3) 1551. D1,2. Domino (思维,构造easy/hard version)

Codeforces Round #734 (Div. 3)

Codeforces Round #734 (Div. 3)-C. Interesting Story-题解

Codeforces Round #734 (Div. 3)-B1. Wonderful Coloring - 1

Codeforces Round #734 (Div. 3)-C. Interesting Story-题解

Codeforces Round #734 (Div. 3)-B1. Wonderful Coloring - 1