CF1540B Tree Array
https://www.luogu.com.cn/problem/CF1540B
VP的时候卡题了QWQ
考虑期望的线性性,可以考虑每一对逆序对
a
>
b
a>b
a>b的概率
求和就是期望
所以肯定是要先枚举两个点 a > b a>b a>b,然后还要枚举第一个点
考虑对于一个确定的根,怎么计算
a
>
b
a>b
a>b的概率
转换一下可以发现如果联通块拓展的点不在a,b路径上时其实是不会对他们之间的概率产生影响的
问题就变成了从根走,先到a的概率
注意到lca以上的时候会使他们两个点距离同时减1,不用管,只用考虑lca到他们两个的距离就可以了
设
f
[
i
]
[
j
]
表
示
距
离
a
为
i
,
b
为
j
的
概
率
显
然
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
+
f
[
i
]
[
j
−
1
]
2
f[i][j]表示距离a为i,b为j的 概率 \\ 显然f[i][j]=\frac{f[i-1][j]+f[i][j-1]}{2}
f[i][j]表示距离a为i,b为j的概率显然f[i][j]=2f[i−1][j]+f[i][j−1]
预处理之后直接用即可
code:
#include<bits/stdc++.h>
#define N 450
#define mod 1000000007
using namespace std;
struct edge {
int v, nxt;
} e[N << 1];
int p[N], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void insert(int u, int v) {
e[eid].v = v;
e[eid].nxt = p[u];
p[u] = eid ++;
}
int qpow(int x, int y) {
int ret = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod) if(y & 1) ret = 1ll * ret * x % mod;
return ret;
}
int n, fa[N][10], dep[N], f[N][N];
const int inv2 = (mod + 1) / 2;
void dfs(int u, int ff) {
fa[u][0] = ff, dep[u] = dep[ff] + 1;
for(int i = 1; i <= 8; i ++) fa[u][i] = fa[fa[u][ i - 1]][i - 1];
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v;
if(v == ff) continue;
dfs(v, u);
}
}
int LCA(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = 8; i >= 0; i --) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if(x == y) return x;
for(int i = 8; i >= 0; i --) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int main() {
init();
scanf("%d", &n);
for(int i = 1; i < n; i ++) {
int u, v;
scanf("%d%d", &u, &v);
insert(u, v), insert(v, u);
}
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] = 1ll * (f[i - 1][j] + f[i][j - 1]) * inv2 % mod;
int ans = 0;
for(int u = 1; u <= n; u ++) {
dfs(u, 0);
for(int i = 1; i <= n; i ++)
for(int j = 1; j < i; j ++) {
int lca = LCA(i, j);
ans = (ans + f[dep[i] - dep[lca]][dep[j] - dep[lca]]) % mod;
}
}
printf("%d", 1ll * ans * qpow(n, mod - 2) % mod);
return 0;
}