题意:
给一棵树,每个点有黑白两种颜色之一,从根节点(度数大于
1
1
)开始随机游走。 你有一个计数器,初始为,然后反复执行一下过程:
1.如果当前点为黑色或者第一次经过,则计数器值加
1
1
。
2.如果当前所在点度数为,结束这个过程。
3.等概率选取一个和当前所在点直接相连的点走过去。
求计数器最后数字的期望,对 998244353 998244353 取模。
题解:
这么经典的题以前居然没做过。。
对于黑白两种颜色分开考虑:
设
pi
p
i
为
i
i
号点在树上的父亲。
对于黑点,此时贡献为期望经过次数,采用期望的方式计算,则有:
fi=colori+∑j,(i,j)∈Vfjdegi
f
i
=
color
i
+
∑
j
,
(
i
,
j
)
∈
V
f
j
d
e
g
i
(叶子节点单独考虑)。
这时候发现拓扑图有环,这里有一种树上不用高斯消元的经典做法:
设
fi=kifpi+bi
f
i
=
k
i
f
p
i
+
b
i
.
DP
DP
时儿子节点的
fj
f
j
可以用
kjfi+bj
k
j
f
i
+
b
j
的形式表达出来,然后就会得到一个只与
fi,fpi
f
i
,
f
p
i
有关的方程,就可以递推上去了,
b1
b
1
即是答案。
下面考虑白点的贡献,白点的贡献为每个白点经过的概率,做树上概率
DP
DP
又有一种经典的方式:
设
fi
f
i
为从
i
i
点出发,走到的概率。
gi
g
i
为从
pi
p
i
出发,走到
i
i
的概率。
有:
gi=1degpi+∑j,(pi,j)∈V,j≠i,j≠ppifj·gidegpi+gpigidegpi g i = 1 d e g p i + ∑ j , ( p i , j ) ∈ V , j ≠ i , j ≠ p p i f j · g i d e g p i + g p i g i d e g p i
那么这道题就得到了解决。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int R_LEN=(1<<18)|1;
char ibuf[R_LEN],*s,*t;
inline char getc(){
(s==t)&&(t=(s=ibuf)+fread(ibuf,1,R_LEN,stdin));
return (s==t)?-1:*s++;
}
inline int rd(){
char ch=getc(); int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1; ch=getc();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0'; ch=getc();}
return i*f;
}
inline void rd(char *c){
char ch=getc();
while(isspace(ch)) ch=getc();
while(!isspace(ch)) *c++=ch, ch=getc();
*c=0; return;
}
const int Mod=998244353;
const int N=1e5+50;
int cnt=0;
inline int power(int a,int b){
int rs=1; a=a%Mod;
for(;b;b>>=1,a=(ll)a*a%Mod) if(b&1) rs=(ll)rs*a%Mod;
return rs;
}
int n,k[N],b[N],f[N],gi[N],col[N],dp[N];
int deg[N],g[N],nt[N*2],vt[N*2],ec;
char ch[N];
inline void adde(int x,int y){nt[++ec]=g[x]; g[x]=ec; vt[ec]=y;}
inline void dfs(int x,int fa){
++cnt;
if(deg[x]==1){
k[x]=0; b[x]=col[x];
f[x]=0; return;
}
int sumk=0, sumb=0, sumf=0;
for(int e=g[x]; e; e=nt[e]){
if(vt[e]==fa) continue;
dfs(vt[e], x);
sumk=(sumk+k[vt[e]])%Mod;
sumb=(sumb+b[vt[e]])%Mod;
sumf=(sumf+f[vt[e]])%Mod;
}
f[x]=power((deg[x]-sumf+Mod)%Mod, Mod-2);
sumf=(col[x]*deg[x]+sumb)%Mod;
sumb=(deg[x]-sumk+Mod)%Mod;
sumb=power(sumb, Mod-2);
k[x]=sumb; b[x]=(ll)sumf*sumb%Mod;
}
inline void dfs2(int x,int fa){
if(deg[x]==1) return;
int sum=gi[x];
for(int e=g[x]; e; e=nt[e]){
if(vt[e]==fa)continue;
sum=(sum+f[vt[e]])%Mod;
}
for(int e=g[x]; e; e=nt[e]){
if(vt[e]==fa)continue;
int tp=((deg[x]-sum+Mod)%Mod+f[vt[e]])%Mod;
gi[vt[e]]=power(tp,Mod-2);
dp[vt[e]]=(ll)dp[x]*gi[vt[e]]%Mod;
}
for(int e=g[x]; e; e=nt[e]){
(vt[e]!=fa) && (dfs2(vt[e],x),0);
}
}
int main(){
n=rd(); rd(ch+1);
for(int i=1; i<=n; i++) col[i]=(ch[i]=='0')? 0: 1;
for(int i=1; i<n; i++){
int x=rd(), y=rd();
adde(x,y); adde(y,x);
++deg[x]; ++deg[y];
} dp[1]=1;
dfs(1,0); dfs2(1,0);
cerr<<cnt<<endl;
int ans=b[1];
for(int i=1;i<=n;i++)
ans=(ans+dp[i]*(!col[i]))%Mod;
printf("%d\n",ans);
}