CF123E Maze 题解

题目传送门

题目大意: 给出一棵树,每个点有两个属性 a , b a,b a,b,设 A = ∑ a , B = ∑ b A=\sum a,B=\sum b A=a,B=b,那么 a A \dfrac a A Aa 就是这个点成为起点的概率, b B \dfrac b B Bb 是这个点成为终点的概率。随机选择一个起点后,这个起点将成为树根,每次只能向下走,到达一个点后,会将这个点的所有儿子随机排序然后依次遍历,走完所有儿子后会回到父亲,走到终点就停止,问起点走到终点期望需要多少步。

题解

这题描述的挺绕的……不过勉强能理解吧qwq

对于一个点 x x x,假如走错了,走到了儿子 y y y,而终点不在 y y y 的子树中,那么就额外走了 2 × s i z e [ y ] 2\times size[y] 2×size[y] 步,假设终点所在子树为儿子 z z z,那么在 x x x 的儿子的排序中, y y y 1 2 \frac 1 2 21 的概率在 z z z 前面,所以每一个儿子被走错的概率都是 1 2 \frac 1 2 21,所以每个儿子提供的期望步数都是 s i z e [ y ] size[y] size[y]

那么考虑每一条边 ( x , y ) (x,y) (x,y),假设 x x x 作为终点,起点在 y y y 的子树中,可以发现,无论起点是谁,总期望步数都是 s i z e [ y ] size[y] size[y](随便画个图走一走就明白了),乘上起点在 y y y 内的概率以及 x x x 成为起点的概率就是这条边的贡献了,全部加起来就是答案。

代码如下:

#include <cstdio>
#define maxn 100010

int n;
struct edge{int y,next;};
edge e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y)
{
	e[++len]=(edge){y,first[x]};
	first[x]=len;
}
double st[maxn],ed[maxn],tot_st=0,tot_ed=0,val[maxn],ans=0;
int size[maxn];
void dfs(int x,int fa)
{
	size[x]=1;val[x]=st[x];
	for(int i=first[x];i;i=e[i].next)
	{
		int y=e[i].y; if(y==fa)continue;
		dfs(y,x);size[x]+=size[y];val[x]+=val[y];
	}
}

int main()
{
	scanf("%d",&n);
	for(int i=1,x,y;i<n;i++)
	scanf("%d %d",&x,&y),buildroad(x,y),buildroad(y,x);
	for(int i=1;i<=n;i++)
	scanf("%lf %lf",&st[i],&ed[i]),tot_st+=st[i],tot_ed+=ed[i];
	for(int i=1;i<=n;i++)st[i]/=tot_st,ed[i]/=tot_ed;
	dfs(1,0);
	for(int x=1;x<=n;x++)
	for(int i=first[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(size[y]<size[x])ans+=val[y]*ed[x]*size[y];
		else ans+=(1-val[x])*ed[x]*(n-size[x]);
	}
	printf("%.10lf",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值