Codeforces 802L Send the Fool Further! (hard)

Description

题面
题目大意:求从根节点出发,每次随机走一个相邻的点,问走到任意一个叶子节点经过的路径长度的期望(走到就停止)

Solution

树上高斯消元,复杂度是 (O(n))
(f[x]) 表示从 (x) 走到任意一个叶子节点路径长度的期望
首先列出转移方程: (f[x]=frac{f[fa]+dis(x,fa)+sum f[son]+dis(x,son)}{in[x]})
对于叶子节点 (f[x]=0)
对于叶子的父亲只有 (f[x])(f[fa]) 两个未知项,我们可以直接把 (f[x]) 代入到父亲的方程中
从而使得父亲的方程也只有两个未知数,一直推到根节点,而根节点没有父亲,直接拿常数项除以系数就是答案

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=1e9+7;
int head[N],nxt[N<<1],to[N<<1],num=0,n,b[N],fa[N],q[N],DFN=0,k[N],in[N];
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline int qm(int x,int k){
	int sum=1;
	while(k){
		if(k&1)sum=1ll*sum*x%mod;
		x=1ll*x*x%mod;k>>=1;
	}
	return sum;
}
inline int inv(int x){return qm(x,mod-2);}
inline void dfs(int x,int last){
	q[++DFN]=x;
	for(int i=head[x];i;i=nxt[i])
		if(to[i]!=last)fa[to[i]]=x,dfs(to[i],x);
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  int x,y,z;
  scanf("%d",&n);
  for(int i=1;i<n;i++){
	  scanf("%d%d%d",&x,&y,&z);x++;y++;
	  link(x,y);link(y,x);k[x]++;k[y]++;
	  b[x]+=z;b[y]+=z;
  }
  for(int i=1;i<=n;i++)in[i]=k[i];
  dfs(1,1);
  for(int i=n;i>=1;i--){
	  int x=q[i];
	  if(in[x]==1)continue;
	  k[fa[x]]=(k[fa[x]]-inv(k[x]))%mod;
	  b[fa[x]]=(b[fa[x]]+1ll*inv(k[x])*b[x])%mod;
  }
  b[1]=1ll*b[1]*inv(k[1])%mod;
  if(b[1]<0)b[1]+=mod;
  printf("%d
",b[1]);
  return 0;
}

原文地址:https://www.cnblogs.com/Yuzao/p/8478111.html