题目链接:https://codeforces.com/contest/1540/problem/B
题目大意:
n个节点的树。初始的时候,等概率随机选择一个点标记,接来随机选择一个与标记点相连的未标记点来标记,直到所有的点都被标记。根据点被标记的顺序,生成一个数列。这个数列的逆序对的期望个数为多少个?
题解:
我们单独计算每对逆序对出现的概率,也就是对于,a在b之前被标记的概率。
我们可以分别计算出每个点第一个选时,逆序对出现的概率。
当点第一个选时,我们可以把点
当作树的根节点。
设为点a和点b的最近公共祖先。
当被标记后,接下来的点的标记情况有三种:
1,标记点与a,b无关
2,标记一个离a更近的点
3,标记一个离b更近的点
显然,标记离a更近的点和标记离b更近的点的概率是相同的
设a距离的距离为x,b距离
的距离为y
那么我们可以把问题抽象为,有两堆物品,第一堆有x个,第二堆有y个,每次等概率的从两堆中选择一堆取走一个物品,求第一堆物品先取完的概率。
我们可以用动态规划计算这个问题。
我们定义为问题的解,那么
复杂度
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int nn =210;
const int inff = 0x3fffffff;
const double eps = 1e-8;
typedef long long LL;
const double pi = acos(-1.0);
const LL mod = 1000000007;
struct node
{
int en,next;
}E[nn*2];
int p[nn];
int num;
int n;
LL POW(LL x,LL y)
{
LL ret=1;
while(y)
{
if(y&1)
ret=(ret*x)%mod;
y/=2;
x=(x*x)%mod;
}
return ret;
}
LL F[nn][nn];
void init()
{
memset(p,-1,sizeof(p));
num=0;
memset(F,0,sizeof(F));
for(int i=1;i<=n;i++)
F[0][i]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
F[i][j]=(F[i-1][j]+F[i][j-1])*POW(2,mod-2)%mod;
}
}
}
void add(int u,int v)
{
E[num].en=v;
E[num].next=p[u];
p[u]=num++;
E[num].en=u;
E[num].next=p[v];
p[v]=num++;
}
int fa[nn][15];
int dep[nn];
void dfs(int id,int pre)
{
for(int i=p[id];i!=-1;i=E[i].next)
{
int en=E[i].en;
if(en==pre)
continue;
dep[en]=dep[id]+1;
fa[en][0]=id;
for(int i=1;i<10;i++)
fa[en][i]=fa[fa[en][i-1]][i-1];
dfs(en,id);
}
}
int lca(int x,int y)
{
if(dep[x]>dep[y])
swap(x,y);
int dis=dep[y]-dep[x];
for(int i=0;(1<<i)<=dis;i++)
{
if(dis&(1<<i))
{
y=fa[y][i];
}
}
while(x!=y)
{
for(int i=0;i<10;i++)
{
if(fa[x][i]==fa[y][i])
{
if(i==0)
{
x=fa[x][0];
y=fa[y][0];
} else {
x=fa[x][i-1];
y=fa[y][i-1];
}
break;
}
}
}
return x;
}
LL solve(int x)
{
for(int i=0;i<10;i++)
fa[x][i]=x;
dep[x]=0;
dfs(x,x);
LL ret=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)
{
int tem=lca(i,j);
//cout<<x<<" "<<i<<" "<<j<<" "<<tem<<endl;
ret=(ret+F[dep[i]-dep[tem]][dep[j]-dep[tem]])%mod;
}
}
return ret;
}
int main()
{
cin>>n;
init();
for(int i=1;i<n;i++)
{
int x,y;
cin>>x>>y;
add(x,y);
}
LL ans=0;
for(int i=1;i<=n;i++)
{
ans=(ans+solve(i))%mod;
}
ans=ans*POW(n,mod-2)%mod;
cout<<ans<<endl;
return 0;
}