解题:SHOI 2014 概率充电器

题面

显然就是在求概率,因为期望乘的全是1.。。。然后就推推推啊

设$fgg[i]$表示这个点父亲没给他充上电的概率,$sgg[i]$表示这个点子树(和它自己没给他充上电的概率),然后这个点没充上电的概率就是$fgg[i]*sgg[i]$

我们发现我们在树上转移的话$fgg$反过来依赖儿子,也就是依赖于$sgg$,那我们先把$sgg$求出来

$sgg[i]=$

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=500005,M=1e6+60;
 6 int p[N],noww[M],goal[M],n,t1,t2,cnt; 
 7 double val[M],pos[N],sgg[N],fgg[N],mem[N],t3,ans;
 8 void Link(int f,int t,double v)
 9 {
10     noww[++cnt]=p[f],p[f]=cnt;
11     goal[cnt]=t,val[cnt]=v;
12 }
13 void Gettre(int nde,int fth)
14 {
15     sgg[nde]=1-pos[nde];
16     for(int i=p[nde];i;i=noww[i])
17         if(goal[i]!=fth)
18         {
19             int g=goal[i]; Gettre(g,nde);
20             mem[g]=sgg[g]+(1-sgg[g])*(1-val[i]);
21             sgg[nde]*=mem[g];
22         }
23 }
24 void Getans(int nde,int fth)
25 {
26     ans-=sgg[nde]*fgg[nde]; 
27     for(int i=p[nde];i;i=noww[i])
28         if(goal[i]!=fth)
29         {
30             int g=goal[i];
31             double fag=sgg[nde]*fgg[nde]/mem[g];
32             fgg[g]=fag+(1-fag)*(1-val[i]),Getans(g,nde);
33         }
34 }
35 int main()
36 {
37     scanf("%d",&n),ans=n;
38     for(int i=1;i<n;i++)
39     {
40         scanf("%d%d%lf",&t1,&t2,&t3);
41         Link(t1,t2,t3/100),Link(t2,t1,t3/100);
42     }
43     for(int i=1;i<=n;i++)
44         scanf("%lf",&pos[i]),pos[i]/=100;
45     Gettre(1,0),fgg[1]=1,Getans(1,0),printf("%.6f",ans);
46     return 0;
47 }
View Code

猜你喜欢

转载自www.cnblogs.com/ydnhaha/p/10283636.html