原题链接
题目大意
有一颗
n
n
n个节点的树,根为
1
1
1,每个节点上有
1
1
1个玻璃球。
对于
v
v
v的任意儿子
u
u
u,
u
u
u的高度比
v
v
v高
1
1
1个单位,因此
u
u
u上的玻璃球可以沿
(
u
,
v
)
(u,v)
(u,v)边滚到
v
v
v。球沿一边滚动需要花费
1
1
1秒。
所有球同时开始滚动。有一些节点时刻储存节点,其中根节点必定是可储存节点,其他节点有 p p p的概率是可储存节点。如果球滚到可储存节点就会立刻破裂,然后从树上取下。如果球初始就在可存储节点上,会立刻破裂。
两个球如果同时滚到同一个节点上就会发生碰撞,不论节点是否是可存储节点,如果发生碰撞,不仅两个球会碎,整个系统也会崩坏,所有滚动都会停止。
如果发生碰撞,则分数为
0
0
0,否则分数为
∑
i
=
1
n
f
(
i
)
\sum^{n}_{i=1}f(i)
∑i=1nf(i),其中
f
(
u
)
f(u)
f(u)表示初始在
u
u
u上的球所有滚过的边数。
求分数的期望。
题解
因为两个球不能同时滚到同一个节点上,所以就相当于某个节点的子节点中,至多有一个点不是存储节点(也可以一个存储节点也没有),才能保证不会有两个球在这个节点上发生碰撞,而每个节点为存储节点的概率为 p p p,假设 i i i节点有 s i z i siz_i sizi个子节点,那么 i i i点不会发生碰撞的概率为: s i z i × ( 1 − p ) × p s i z i − 1 ( siz_i\times (1-p)\times p^{siz_i-1}( sizi×(1−p)×psizi−1( 有一个存储子节点 ) + )+ )+ p s i z i ( p^{siz_i}( psizi(没有存储子节点 ) ) )。
所以整颗树不发生碰撞的概率为
P
P
P,则
P
P
P为:
P
=
∏
i
s
i
z
i
×
(
1
−
p
)
×
p
s
i
z
i
−
1
+
p
s
i
z
i
P=\prod_{i}siz_i\times (1-p)\times p^{siz_i-1}+p^{siz_i}
P=i∏sizi×(1−p)×psizi−1+psizi
假设
d
p
x
dp_x
dpx表示节点
x
x
x上球的期望,
y
y
y表示其父节点,如果节点
x
x
x上的球可以滚到
y
y
y,则此时
d
p
x
=
d
p
y
+
1
dp_x=dp_y+1
dpx=dpy+1。但是此时可能为非法情况(该节点为存储节点),所以我们还需要考虑情况是否合法。
节点
x
x
x不是存储节点的概率为:
(
1
−
p
)
×
p
s
i
z
y
−
1
(1-p)\times p^{siz_y-1}
(1−p)×psizy−1
同时还要保证
y
y
y节点中有一个子节点不是存储节点,其概率为:
s
i
z
y
×
(
1
−
p
)
×
p
s
i
z
y
−
1
+
p
s
i
z
y
siz_y\times (1-p)\times p^{siz_y-1}+p^{siz_y}
sizy×(1−p)×psizy−1+psizy。
所以得到最终转移式:
d
p
x
=
(
d
p
y
+
1
)
×
(
1
−
p
)
×
p
s
i
z
y
−
1
s
i
z
y
×
(
1
−
p
)
×
p
s
i
z
y
−
1
+
p
s
i
z
y
dp_x=(dp_y+1)\times \frac{(1-p)\times p^{siz_y-1}}{siz_y\times (1-p)\times p^{siz_y-1}+p^{siz_y}}
dpx=(dpy+1)×sizy×(1−p)×psizy−1+psizy(1−p)×psizy−1
在最终计算答案时,需保证整棵树的合法性,所以答案为:
a
n
s
=
P
×
∑
d
p
x
ans=P\times \sum dp_x
ans=P×∑dpx
参考代码
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define FOR(i,n,m) for(int i=n;i<=m;i++)
#define mod 998244353
using namespace std;
const int N=5e5+5;
int powmod(int a,int b)
{
int ret=1;
while(b)
{
if(b&1)ret=1ll*ret*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ret;
}
int n,p,P=1;
int siz[N],dp[N],ans=0;
vector<int> e[N];
void dfs1(int x)
{
int son;
if(e[x].empty())return;
FOR(i,0,e[x].size()-1)
{
son=e[x][i];
dfs1(son);
}
P=1ll*P*((1ll*siz[x]*(1-p+mod)%mod*powmod(p,siz[x]-1)%mod+powmod(p,siz[x]))%mod)%mod;
}
//遍历每个节点并计算整棵树合法的概率P
void w(int x,int fa)
{
int son;
dp[x]=1ll*(1+dp[fa])*(1-p+mod)%mod*powmod(p,siz[fa]-1)%mod*powmod(1ll*siz[fa]*(1-p+mod)%mod*powmod(p,siz[fa]-1)%mod+powmod(p,siz[fa]),mod-2)%mod;
if(e[x].empty())return;
FOR(i,0,e[x].size()-1)
{
son=e[x][i];
w(son,x);
}
}
//计算每个节点的期望值dp[x]
int main()
{
scanf("%d%d",&n,&p);
if(n==1){puts("0");return 0;}
FOR(u,2,n)
{
int v;
scanf("%d",&v);
e[v].pb(u);
}
FOR(i,1,n)siz[i]=e[i].size();//每个节点的子节点数
dfs1(1);
FOR(i,0,e[1].size()-1)w(e[1][i],1);
FOR(i,1,n)ans=(1ll*ans+dp[i])%mod;
printf("%d",1ll*P*ans%mod);
}