Tree Array

Tree Array

一道简单但有趣的期望\(DP\),套路的,先枚举一个根,再计算答案。考虑到我只想知道 \(i < j\)\(time_i > time_j\) 的个数,不妨枚举\(i, j\),计算\(i\)后出现的概率,求和即为答案。
对于\(i,j\),我们只关心他们的相对出现时间,那么对此有影响的便是\(LCA_{i,j}\)下方的点。设\(f_{x,y}\)表示\(i\)\(lca\)间有\(x\)个点,\(j\)\(lca\)间有\(y\)个点,使得\(i\)先出现的概率。因为对于每个点出现的概率是相同的,所以\(f_{x,y} = \frac{f_{x - 1,y} + f_{x, y - 1}}{2}\),初值为\(f_{0,i} = 1\)。总时间复杂度为\(O(n^3logn)\)

Code
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N = 205, P = 1e9 + 7;
int h[N], tot, n, g[N][N], f[N][15], dep[N];

struct edge{int to, nxt;}e[N << 1];
void add(int x, int y){e[++tot] = edge{y, h[x]}, h[x] = tot;}
LL fpow(LL x, LL y) { 
	LL res = 1;
	for (; x; x >>= 1, y = y * y % P)
		if (x & 1) res = res * y % P;
	return res;
}
void dfs(int u, int fa) {
	dep[u] = dep[fa] + 1, f[u][0] = fa;
	for (int i = 1; i <= 10; i++) f[u][i] = f[f[u][i - 1]][i - 1];
	for (int i = h[u]; i; i = e[i].nxt)
		if (e[i].to ^ fa) dfs(e[i].to, u);
}
int lca(int x, int y) {
	if (dep[x] > dep[y]) swap(x, y);
	int tmp = dep[y] - dep[x];
	for (int i = 0; tmp; tmp >>= 1, i++) (tmp & 1) && (y = f[y][i]);
	if (x == y) return dep[x];
	for (int i = 10; i >= 0; i--) (f[x][i] ^ f[y][i]) && (x = f[x][i], y = f[y][i]);
	return dep[f[x][0]];
}
int main() {
	scanf("%d",&n);
	for (int i = 1, q, p; i < n; i++) scanf("%d%d",&q,&p), add(q, p), add(p, q);
	for (int i = 1; i <= n; i++) g[0][i] = 1;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			g[i][j] = (g[i - 1][j] + g[i][j - 1]) * fpow(P - 2, 2LL) % P;
	LL ans = 0;
	for (int i = 1; i <= n; i++) {
		dfs(i, 0);
		for (int j = 1; j <= n; j++)
			for (int k = j + 1, x; k <= n; k++)
				x = lca(j, k), (ans += g[dep[k] - x][dep[j] - x]) %= P;	
	}
	printf("%lld\n", ans * fpow(P - 2, (LL)n) % P);
}

posted @ 2022-11-25 19:31  RiverSheep  阅读(48)  评论(0)    收藏  举报