Codeforces Round #728 (Div. 2) D. Tree Array(期望+枚举)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #728 (Div. 2) D. Tree Array(期望+枚举)相关的知识,希望对你有一定的参考价值。

LINK

用了一个非常劣的方法卡过去了…

考虑枚举第一个被染色的点 r o o t root root

那么以 r o o t root root为根去遍历整棵树,枚举每对点对 ( u , v ) (u,v) (u,v)计算贡献

u u u v v v的儿子且满足 v > u v>u v>u,答案直接加一(只有祖先节点被标记自己才会被标记)

v v v u u u的儿子且满足 u > v u>v u>v,答案直接加一

否则求一个 u , v u,v u,v l c a lca lca x x x,那么考虑 x x x被染色,接下来想染色 u , v u,v u,v需要走不同的分支

x x x u u u需要 q q q步, x x x v v v需要 w w w

u > v u>v u>v时答案加上 f [ q ] [ w ] f[q][w] f[q][w]

v > u v>u v>u时答案加上 f [ w ] [ q ] f[w][q] f[w][q]

其中 f [ i ] [ j ] f[i][j] f[i][j]表示第一个点的 i i i级祖先被染色,第二个点的 j j j级祖先被染色

此时随机染色,第一个点先被染色的概率.

那么这个 f f f数组可以直接用一个暴力的 O ( n 4 ) O(n^4) O(n4) d p dp dp处理出来

void init()
{
	int pro = quick(2,mod-2);
	for(int i=1;i<=200;i++)
	for(int j=i;j+i<=200;j++)//枚举计算f[i][j] 
	{
		sf[0][0] = 1;//一开始两个点进度都为0 
		for(int q=0;q<i;q++)
		for(int w=0;w<j;w++)//第一个点染色了q次,第二个点染色了w次.显然q,w不能是i,j,否则就终止了,状态不能转移 
		{
			int x = 1ll*sf[q][w]*pro%mod;
			sf[q+1][w] = ( 1ll*sf[q+1][w]+x )%mod;
			sf[q][w+1] = ( 1ll*sf[q][w+1]+x )%mod;	
		}
		for(int w=0;w<j;w++)	f[i][j] = ( f[i][j]+sf[i][w] )%mod;
		if( i!=j )
			for(int q=0;q<i;q++)	f[j][i] = ( f[j][i]+sf[q][j] )%mod;
		
		for(int q=0;q<=i;q++)
		for(int w=0;w<=j;w++)
			sf[q][w] = 0;
	} 
}
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
const int mod = 1e9+7;
const int maxn = 209;
int n,pro;
vector<int>vec[maxn];
int quick(int x,int n)
{
	int ans = 1;
	for( ; n ; n>>=1,x=1ll*x*x%mod )
		if( n&1 )	ans = 1ll*ans*x%mod;
	return ans;
}
int f[209][209],sf[209][209];
void init()
{
	int pro = quick(2,mod-2);
	for(int i=1;i<=200;i++)
	for(int j=i;j+i<=200;j++)//枚举计算f[i][j] 
	{
		sf[0][0] = 1;//一开始两个点进度都为0 
		for(int q=0;q<i;q++)
		for(int w=0;w<j;w++)//第一个点染色了q次,第二个点染色了w次.显然q,w不能是i,j,否则就终止了,状态不能转移 
		{
			int x = 1ll*sf[q][w]*pro%mod;
			sf[q+1][w] = ( 1ll*sf[q+1][w]+x )%mod;
			sf[q][w+1] = ( 1ll*sf[q][w+1]+x )%mod;	
		}
		for(int w=0;w<j;w++)	f[i][j] = ( f[i][j]+sf[i][w] )%mod;
		if( i!=j )
			for(int q=0;q<i;q++)	f[j][i] = ( f[j][i]+sf[q][j] )%mod;
		
		for(int q=0;q<=i;q++)
		for(int w=0;w<=j;w++)
			sf[q][w] = 0;
	} 
}
int fa[maxn][22],deep[maxn];
int lca(int x,int y)
{
	if( deep[x]<deep[y] )	swap(x,y);
	for(int i=20;i>=0;i--)
		if( deep[fa[x][i]]>=deep[y] )	x = fa[x][i];
	if( x==y )	return x;
	for(int i=20;i>=0;i--)
		if( fa[x][i]!=fa[y][i])		x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}
int get_dis(int x,int y)
{
	int u=lca(x,y);
	return deep[x]+deep[y]-2*deep[u];
}
void predfs(int u,int father)
{
	fa[u][0] = father; deep[u] = deep[father]+1;
	for(int i=1;i<=20;i++)
		fa[u][i] = fa[fa[u][i-1]][i-1];
	for( auto v:vec[u] )
		if( v!=father )	predfs(v,u);
}
int solve()
{
	int ans = 0;
	for(int u=1;u<=n;u++)
	for(int i=u+1;i<=n;i++)
	{
		int x = lca(u,i), q = get_dis(i,x), w = get_dis(u,x);
		if( x==u )	ans = ( ans+(u>i) )%mod;
		else if( x==i )	ans = ( ans+(i>u) )%mod;
		else
		{
			if( i>u )	ans = ( ans+f[q][w] )%mod;
			else	ans = ( ans+f[w][q] )%mod;
		}
	}
	return ans;
}
signed main()
{
	init();
	cin >> n;
	for(int i=1;i<n;i++)
	{
		int l,r; cin >> l >> r;
		vec[l].push_back( r );
		vec[r].push_back( l );
	}
	int res = 0;
	for(int i=1;i<=n;i++)
	{
		predfs(i,0);
		res = ( 1ll*res+1ll*solve()*quick(n,mod-2)%mod )%mod;
	}
	cout << ( res%mod+mod )%mod;
	return 0;
}

以上是关于Codeforces Round #728 (Div. 2) D. Tree Array(期望+枚举)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #728 (Div. 2) D. Tree Array(期望+枚举)

Codeforces Round #436 E. Fire(背包dp+输出路径)

[ACM]Codeforces Round #534 (Div. 2)

Codeforces Round #726 (Div. 2) B. Bad Boy(贪心)

Codeforces Global Round 19

Codeforces Educational Codeforces Round 67