[SHOI2014] 概率充电器
Description
給定一棵\(N(N\leq 5\times 10^5)\)個(gè)節(jié)點(diǎn)的樹(shù)。每個(gè)點(diǎn)有概率被直接充電,每條邊有概率導(dǎo)電。如果一個(gè)沒(méi)有被直接充電的點(diǎn)通過(guò)一條導(dǎo)電的邊連接到了某個(gè)被充電的點(diǎn),那么這個(gè)點(diǎn)也會(huì)被充電。問(wèn)期望充電的點(diǎn)的個(gè)數(shù)。
Solution
由期望線性性,我們可以求出每個(gè)點(diǎn)被充電的概率,最后求和即可。
節(jié)點(diǎn)\(i\)通電有三種可能
可以兩遍\(dfs\)做,第一遍先求出第一種和第二種的概率,再換根\(dfs\)加上第三種的概率就行了。這是最開(kāi)始的\(naive\)想法。
但是這些情況發(fā)生的概率不能直接加起來(lái)。考慮兩個(gè)事件\(A,B\),發(fā)生的概率分別是\(P(A),P(B)\),那么至少發(fā)生一件的概率是\(P(A)+P(B)-P(A)*P(B)\)。
證明就是枚舉三種情況:
三種情況求和就是\(P(A)+P(B)-P(A)*P(B)\)了。
知道了這個(gè)做兩遍\(dfs\)就行了剛做過(guò)一個(gè)差不多的
啊Typora代碼框里的字體好好看啊誰(shuí)知道這是什么字體啊求告知QAQ
Code
#include<set> #include<map> #include<cmath> #include<queue> #include<cctype> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using std::min; using std::max; using std::swap; using std::vector; const int N=500005; typedef double db; typedef long long ll; #define pb(A) push_back(A) #define pii std::pair<int,int> #define all(A) A.begin(),A.end() #define mp(A,B) std::make_pair(A,B)db f[N],p[N]; int n,cnt,head[N];struct Edge{int to,nxt;db dis; }edge[N<<1];void add(int x,int y,db z){edge[++cnt].to=y;edge[cnt].nxt=head[x];edge[cnt].dis=z;head[x]=cnt; }int getint(){int X=0,w=0;char ch=0;while(!isdigit(ch))w|=ch=='-',ch=getchar();while( isdigit(ch))X=X*10+ch-48,ch=getchar();if(w) return -X;return X; }void dfs(int now,int fa){f[now]=p[now];for(int i=head[now];i;i=edge[i].nxt){int to=edge[i].to;if(to==fa) continue;dfs(to,now);f[now]=f[now]+f[to]*edge[i].dis-f[now]*f[to]*edge[i].dis;} }void dfs(int now,int fa,db dis){if(f[now]*dis!=1){db x=(f[fa]-f[now]*dis)/(1-f[now]*dis);f[now]=f[now]+x*dis-f[now]*x*dis;} else f[now]=1;for(int i=head[now];i;i=edge[i].nxt){int to=edge[i].to;if(to==fa) continue;dfs(to,now,edge[i].dis);} }signed main(){n=getint();for(int i=1;i<n;i++){int x=getint(),y=getint(),z=getint();add(x,y,0.01*z),add(y,x,0.01*z);}for(int i=1;i<=n;i++) p[i]=0.01*getint();dfs(1,0);for(int i=head[1];i;i=edge[i].nxt)dfs(edge[i].to,1,edge[i].dis);db ans=0;for(int i=1;i<=n;i++) ans+=f[i];printf("%.6lf\n",ans);return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/YoungNeal/p/9858799.html
總結(jié)
以上是生活随笔為你收集整理的[SHOI2014] 概率充电器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Django学习笔记2
- 下一篇: 【驱动】使用结构体 file_opera