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\n",b[1]);
  return 0;
}

转载于:https://www.cnblogs.com/Yuzao/p/8478111.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值