LG P4284 [SHOI2014]概率充电器
Description
著名的电子产品品牌SHOI 刚刚发布了引领世界潮流的下一代电子产品—— 概率充电器:
“采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决 定!SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看 吧!”
SHOI 概率充电器由$n-1$条导线连通了$n$ 个充电元件。进行充电时,每条导 线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率 决定。随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行 间接充电。
作为SHOI 公司的忠实客户,你无法抑制自己购买SHOI 产品的冲动。在排 了一个星期的长队之后终于入手了最新型号的SHOI 概率充电器。你迫不及待 地将SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件 个数的期望是多少呢?
Solution
每个点能否被充电与其子树和子树外都有关,首先考虑子树内
$$dp_{u}=\prod _{v \in son_{u}} dp_v+(1-dp_v) \times (1-p_{u,v}) $$
再考虑子树外对概率的影响,因为$dp$由连乘计算得到,所以
$$fa_v =\frac{fa_u \times dp_u }{dp_v+(1-dp_v)(1-p_{u,v})}$$
#include<iostream> #include<cstdio> using namespace std; int n,tot,head[1000005]; double q[500005],dp[500005],fa[500005],ans; struct Edge { int to,nxt; double w; }edge[1000005]; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } void dfs1(int k,int f) { dp[k]=1-q[k]; for(int i=head[k];i;i=edge[i].nxt) { int v=edge[i].to; if(v!=f) { dfs1(v,k); dp[k]*=dp[v]+(1-dp[v])*(1-edge[i].w); } } } void dfs2(int k,int f) { for(int i=head[k];i;i=edge[i].nxt) { int v=edge[i].to; if(v!=f) { double temp=fa[k]*dp[k]/(dp[v]+(1-dp[v])*(1-edge[i].w)); fa[v]=temp+(1-temp)*(1-edge[i].w); dfs2(v,k); } } } int main() { n=read(); for(int i=1;i<n;i++) { int a=read(),b=read(); double p=read(); edge[++tot]=(Edge){b,head[a],p/100}; head[a]=tot; edge[++tot]=(Edge){a,head[b],p/100}; head[b]=tot; } for(int i=1;i<=n;i++) { double x=read(); q[i]=x/100; } dfs1(1,0); fa[1]=1; dfs2(1,0); for(int i=1;i<=n;i++) { ans+=1-dp[i]*fa[i]; } printf("%.6lf\n",ans); return 0; }