题目描述
一棵\(n\)个节点的树,从1号结点开始游戏,在每一个点\(x\):
- 有\(a[x]/100\)的可能掉进陷阱死翘翘回到1重新开始
- 有\(b[x]/100\)的可能找到出口并结束游戏
- 剩下的可能中,你等概率随机选一条和它相连的边(可以是父亲)走过去
问期望多少步结束游戏
\(1\leq T \leq 30,1\leq n \leq 10000\)
分析
设\(dp[x]\)表示位于\(x\)节点时,期望走几步才能结束游戏
那么\(dp[x]=0.01a[x]*dp[1]+0.01b[x]*0+0.01(1-a[x]-b[x])*(\frac{1}{cnt}(\sum dp[son]+dp[1]+1))\)
看了一下数据范围发现并不能承受高斯消元的时间复杂度
我们发现,每一个点的\(dp\)值之和父亲、1号点还有儿子有关,那么叶子节点的\(dp\)值可以用父亲和1号点表示,这样往上代,合并同类项之后可以发现,每一个点的值都可以表示为:
\(dp[x]=...*dp[1]+...*dp[fa[x]]+...\)(常数项)
所以只需要维护一下每一项的系数就可以\(O(n)\)求解了,记得特判Impossible
代码
void SEARCH(int x,int pa){
f[x][0]=f[x][1]=f[x][2]=0;
int cnt=0;
for(int r=lst[x];r;r=nxt[r]){
cnt++;
if(edge[r]==pa)continue;
SEARCH(edge[r],x);
}
DB lef=(100-a[x]-b[x])*0.01;
DB hlp=0;
for(int r=lst[x];r;r=nxt[r]){
if(edge[r]==pa)continue;
int pos=edge[r];
f[x][0]+=f[pos][0];
f[x][2]+=f[pos][2];
hlp+=f[pos][1];
}
f[x][0]=(lef*f[x][0])/(1.0*cnt)+a[x]*0.01;
f[x][2]=(lef*f[x][2])/(1.0*cnt)+lef;
if(x==1)f[x][1]=0;else f[x][1]=lef/(1.0*cnt);
hlp=hlp*lef/(1.0*cnt);
hlp=1.0-hlp;
if(x==1)hlp-=f[x][0];
if(hlp<=0)f[x][0]=f[x][1]=f[x][2]=0;
else rep(i,0,2)f[x][i]/=hlp;
}
原文地址:https://www.cnblogs.com/SCL123/p/11831202.html
时间: 2024-11-08 20:32:43