[SHOI2014] 概率充电器

题意:

给定一棵n个点的树,每个点有$q_u$的概率亮,每条边有$p_{u,v}$的概率存在。

如果一个连通块里有亮的点那么这个连通块里所有点都变成亮的。

问期望有多少个点是亮的。

$n\leq 500000$。

 

题解:

一开始按照传统dp那样推了……其实树上期望的题一般都不是传统题。

用期望的线性性拆一下,其实就是求每个点被点亮的概率之和。

考虑设$f_u$表示u被点亮的概率,但这东西有点难求,需要容斥。

于是直接设$f_u$表示u没被点亮的概率,那么有$f_u = (1- q_u )\prod f_v + p_{u,v}(1-f_v )$。

发现如果直接树形dp的话父子时间会互相影响,这数据范围也做不了高斯消元。

于是考虑换根dp,直接dfs一遍算出点1的答案,然后再dfs一遍往下算答案即可。

复杂度$O(n)$。

 

套路:

  • 较复杂的期望dp$\rightarrow$先用线性性拆一下。
  • 求期望合法的个数$\rightarrow$求每个合法的概率之和。
  • 期望的本质就是算概率。
  • 换根dp$\rightarrow$先dfs一遍算出根的答案,再把每个点的原答案加上父亲的答案去掉它的贡献。

 

代码:

#include<bits/stdc++.h>
#define maxn 500005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long
#define rint register int
#define debug(x) cerr<<#x<<": "<<x<<endl
#define fgx cerr<<"--------------"<<endl
#define dgx cerr<<"=============="<<endl

using namespace std;
int n,hd[maxn],to[maxn<<1],nxt[maxn<<1],cnt;
double P[maxn<<1],Q[maxn],F[maxn],G[maxn];

inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

inline void addedge(int u,int v,double p){
    to[++cnt]=v,P[cnt]=p,nxt[cnt]=hd[u],hd[u]=cnt;
    to[++cnt]=u,P[cnt]=p,nxt[cnt]=hd[v],hd[v]=cnt;
}

inline void dfs1(int u,int fa){
    F[u]=1.0-Q[u];
    for(int i=hd[u];i;i=nxt[i]){
        int v=to[i]; double p=P[i];
        if(v==fa) continue; dfs1(v,u);
        F[u]*=(1.0+p*(F[v]-1.0));
    }
}
inline void dfs2(int u,int fa){
    if(u==1) G[u]=F[u];
    for(int i=hd[u];i;i=nxt[i]){
        int v=to[i]; double p=P[i];
        if(v==fa) continue;
        if((1.0+p*(F[v]-1.0)==0)){cout<<n<<".000000"<<endl,exit(0);}
        double tp=G[u]/(1.0+p*(F[v]-1.0));
        G[v]=F[v]*(1.0+p*(tp-1.0)),dfs2(v,u);
    }
}

int main(){
    n=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read(),p=read();
        addedge(u,v,p/100.0);
    }
    for(int i=1;i<=n;i++) Q[i]=read()/100.0;
    dfs1(1,0),dfs2(1,0);
    double ans=0;
    for(int i=1;i<=n;i++) ans+=1.0-G[i];
    printf("%.6lf\n",ans);
    return 0;
}
概率充电器

 

posted @ 2020-07-15 23:07  Fugtemypt  阅读(154)  评论(0编辑  收藏  举报