CF697D-Puzzles

题目

一棵树,从根节点开始dfs,每层以随机顺序进入每个子节点,问走到每个点的时候期望经过了多少个点。

(这里经过多少个点指的是经过多少个不同的点,即经过一个点多次算一个)

(其实这个题不如说求期望dfn序)。

\(n\le 10^5\)

分析

一个很明显的思路就是:\(f[x]=1+f[fa]+绕来绕去期望经过的点个数\) 。从上往下dfs,问题就转化成了如何求每一个点\(x\)进入其子节点\(v\)之前期望经过的点个数。设绕来

绕去期望经过点个数为\(g[x]\) ,它的父亲有\(n\)个子节点。

计算这个东西有两种思路:

思路1

注意到这是一个dfs,所以我们如果进了一颗子树,那么它会走完整个子树再出来,而这个子树之前是没有走过的,即点数增加了\(\text{size}[v]\) 。(\(v\)为与\(x\)同父亲的点)

这样我们就可以通过枚举之前走进了多少个子树来求:
\[ \begin{aligned} g[x]&=\sum _{i=1}^{n-1} 任意不含x的i个的size的和*\frac{1}{n}*\frac{1}{n-1}*\cdots*\frac{1}{n-i} \\ &=\sum _{i=1}^{n-1} \frac{(n-i-1)!}{n!}\sum _{v\ne x}i*size[v]* A_{n-2}^{i-1} \\ &=\sum _{i=1}^{n-1} \frac{(n-i-1)!}{n!}\sum _{v\ne x}i*size[v]* \frac{(n-2)!}{(n-i-1)!} \\ &=\sum _{v\ne x}size[v] \sum _{i=1}^{n-1}\frac{(n-2)!}{n!} \\ &=\frac{1}{2}\sum _{v\ne x}size[v] \end{aligned} \]

思路2

把从\(x\)父亲进入这一层的顺序列出来,所有情况是它的全排列。\(x\)前面有\(i\)个数的概率为\(\frac{1}{n}\), 前面\(i\)个数的和的期望为\(\frac{i\sum _{v\ne x}size[v]}{n-1}\),所以所有情况为
\[ \begin{aligned} g[x]&=\frac{1}{n}*\frac{\sum _{i=1}^{n-1}i\sum _{v\ne x}size[v]}{n-1} \\ &=\frac{1}{2}\sum _{v\ne x}size[v] \end{aligned} \]

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=1e5+1;
vector<int> g[maxn];
double f[maxn];
int size[maxn];
inline void add(int x,int y) {g[x].push_back(y);}
int Size(int x) {
    int &sz=size[x]=1;
    for (int v:g[x]) sz+=Size(v);
    return sz;
}
void dfs(int x) {
    for (int v:g[x]) f[v]=1.0+f[x]+(double)(size[x]-size[v]-1)/2.0,dfs(v);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    int n=read();
    for (int i=2;i<=n;++i) add(read(),i);
    f[1]=1;
    Size(1);
    dfs(1);
    for (int i=1;i<=n;++i) printf("%.2lf%c",f[i]," \n"[i==n]);
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/7143432.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值