Codeforces Round #728 (Div. 2) D. Tree Array(期望+枚举)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #728 (Div. 2) D. Tree Array(期望+枚举)相关的知识,希望对你有一定的参考价值。
用了一个非常劣的方法卡过去了…
考虑枚举第一个被染色的点 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)