Description
有 (n(nle 5 imes10^5)) 个元件 和 (n-1) 条充电线,每个电线有一定概率通电,每个元件有一定概率自己有电,求有电的元件的期望个数
Solution
当前原件 (x) 充电的概率 (f_x) 为
[sum_{(x,y)in E} f_y imes p_{x,y}+ d_x
]
考虑高斯消元,时间复杂度 (O(n^3))
期望得分?((O(n^3)) 过 (5 imes10^5))
发现这是一棵树,并不是一张图,所以考虑换根法
定义 (f_{i}) 为当前点的通电概率
那么 (ans=sumlimits_{i=1}^n f_i)
这题目的最大收获
概率与概率相互独立,计算时可以考虑 (f_{i}=(1-f_{i}) imes calc(t))
这样可以避免 (f_i >1) 的情况
子树里面的很套路,关键是子树外面的(这里我一开始卡了好久好久)
[f_{t}=frac{(f_{x}-f_{t} imes p_{x,t})}{1-f_t imes p_{x,t}} imes(1-f_t) imes p_{x,t}
]
其实没想到的是分母的部分,直接拆掉组成所占比例除一下挺妙的
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
#define For(i,a,b) for(reg int i=a;i<=b;++i)
#define Down(i,a,b) for(reg int i=a;i>=b;--i)
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=5e5+10;
struct node{
int to,nxt; double p;
}e[N<<1];
int head[N],cnt,n;
inline void add(int u,int v,double p)
{
e[++cnt].to=v; e[cnt].nxt=head[u]; e[cnt].p=p/100;
return head[u]=cnt,void();
}
double f[N],ans;
inline void dfs1(int x,int fa)
{
for(int i=head[x];i;i=e[i].nxt)
{
int t=e[i].to; if(t==fa) continue;
dfs1(t,x); f[x]+=f[t]*e[i].p*(1-f[x]);
}
return ;
}
inline void dfs2(int x,int fa)
{
for(int i=head[x];i;i=e[i].nxt)
{
int t=e[i].to; if(t==fa) continue;
if(f[t]*e[i].p!=1) f[t]+=(1-f[t])*(f[x]-f[t]*e[i].p)/(1-f[t]*e[i].p)*e[i].p;
dfs2(t,x);
}return ;
}
signed main()
{
n=read(); For(i,1,n-1){int u=read(),v=read(),w=read(); add(u,v,w),add(v,u,w);}
For(i,1,n) f[i]=1.0*read()/100;
dfs1(1,0); dfs2(1,0);
For(i,1,n) ans+=f[i];
printf("%.6lf
",ans);
return 0;
}
}signed main(){return yspm::main();}