出处[辗转山河弋流歌 by 空灰冰魂]
著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器:“采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定! SHOI 概率充电器,您生活不可或缺的必需品!能充上电吗?现在就试试看 吧!”SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件。进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率 决定。随后电能可以从直接充电的元件经过通电的导线使得其他充电元件进行间接充电。作为 SHOI 公司的忠实客户,你无法抑制自己购买 SHOI 产品的冲动。在排了一个星期的长队之后终于入手了最新型号的 SHOI 概率充电器。你迫不及待 地将 SHOI 概率充电器插入电源——这时你突然想知道,进入充电状态的元件个数的期望是多少呢?输入第一行一个整数:
n
n
n。概率充电器的充电元件个数。充电元件由
1
−
n
1-n
1−n 编号。之后的 n-1 行每行三个整数
a
,
b
,
p
a, b, p
a,b,p,描述了一根导线连接了编号为
a
a
a 和
b
b
b 的充电元件,通电概率为 p%。第
n
+
2
n+2
n+2 行
n
n
n 个整数:
q
i
qi
qi。表示 i 号元件直接充电的概率为 qi%。输出输出一行一个实数,为能进入充电状态的元件个数的期望,四舍五入到小数点后 6 位小数。
样例输入1
3
1 2 50
1 3 50
50 0 0
样例输出1
1.000000
样例输入1
5
1 2 90
1 3 80
1 4 70
1 5 60
100 10 20 30 40
样例输出2
4.300000
提示
【数据规模】对于 30%的数据, n≤5000。对于 100%的数据, n≤500000, 0≤p,qi≤100。
CODE
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
struct fjy{
int nxt,v;
double w;
}e[N<<1];
int cnt,fir[N],fa[N];
double p[N],h[N],g[N],ans=0.0;//p[i]表示以i为根的子树中通电节点的期望值,g[i]表示i的父节点对i的通电节点个数期望的贡献,h[i]表示以i为根结点的子树对i的父节点通电节点个数期望的贡献
void add(int u,int v,double w){
e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=fir[u];fir[u]=cnt;
}
int ui,vi,wi,c,n;
void dfs1(int u,int f){
fa[u]=f;
for(int i=fir[u];i;i=e[i].nxt){
if(e[i].v==f) continue;
dfs1(e[i].v,u);
h[e[i].v]=p[e[i].v]+(1.00-p[e[i].v])*(1-e[i].w);//由于对父节点做的贡献需要统计完过后再做,故在处理父节点时计算
p[u]*=h[e[i].v];
}
}
void dfs(int u,int f){
ans+=1.0-p[u]*g[u];
for(int i=fir[u];i;i=e[i].nxt){
if(e[i].v==fa[u]) continue;
double t=h[e[i].v]<1e-6?0.0:g[u]*p[u]/h[e[i].v];
g[e[i].v]=t+(1.0-t)*(1.0-e[i].w);
dfs(e[i].v,u);
}
}
int main(){
int size=100<<20;
__asm__("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//此处要开手工栈
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d%d",&ui,&vi,&wi);
add(ui,vi,wi/100.0),add(vi,ui,wi/100.0);
}
for(int i=1;i<=n;i++){
scanf("%d",&c);
p[i]=double(1.0-c/100.0);
}
dfs1(1,0); g[1]=1.0;
dfs(1,0);
//for(int i=1;i<=n;i++) ans+=1-p[i]*g[i];
printf("%.6lf",ans);
exit(0);//开手工栈无法用return退出
return 0;
}