\(\\\)

\(Description\)


一个含\(N\)个元器件的树形结构充电器,第\(i\)个元器件有\(P_i\)的概率直接从外部被充电,连接\(i,j\)的边有\(P_{i,j}\)的概率导电,元器件只有外部充电和从已充电元器件导电两种方式被充电,求最后被充电的元器件个数的期望。

  • \(N\in [0,5\times10^5]\),\(P_i,P_{ij}\in [0,1]\)

\(\\\)

\(Solution\ (1)\)


  • 期望\(=\)贡献\(\times\)概率,而个数的贡献只能为\(1\),所以被点亮元器件个数的期望\(=\)每个元器件被点亮概率之和。

  • 因为是无根树,所以要换根进行两次\(DP\),假设树的形态定为以\(1\)为根。设\(f[i]\)表示只考虑当前节点和所有当前节点子树的节点,当前节点被点亮的概率,设\(g[i]\)表示只考虑除掉当前节点和所有当前节点子树的节点剩下的节点,当前节点被点亮的概率。两遍\(DFS\)分别处理\(f[i]\)和\(g[i]\)。

  • 考虑\(f[i]\)的求法,应当是自底向上的。首先当前节点自己点亮的概率显然是\(P_i\),剩下需要考虑的就是子树对根节点的影响。需要注意的是,不同子树对根的影响虽然是"或"的关系,但却不是互斥的。也就是说,如果暴力的累加每一个子树的贡献,多个子树同时做出贡献的部分会被计算多次,因为直接累加一棵子树的贡献正确的前提是其他子树都不能做出贡献,即都不能将根节点点亮。一种做法是容斥计算,还有一种更简便的方法是正难则反。注意到当前点被点亮的概率\(=1-\)不被点亮的概率,而不被点亮的条件是"与"的关系,也就是说不被点亮的部分是可以连乘得到的,于是有:

    \[f[i]=1-(1-P_i)\times \prod_{v\in son[i]}(1-f[v]\times P_{i,v})
    \]

  • 对于\(g[i]\)的求法就是换根那一套了。但是这次只有\(1\)号节点的\(g\)是确定为\(0\),所以自上向下更新。考虑对于一个子节点,其\(g\)值可以表示为两部分,被父节点的\(g\)部分点亮,或是父节点被其他子树点亮,再点亮当前节点,同样的,它们之间是"或"的关系,容斥起来非常麻烦。转化之后只需考虑如何从父节点的\(f\)值中去掉当前节点的部分,发现在累乘时关于当前节点的一项是独立的,可以直接去掉,于是有:

    \[g[i]=\big(1-(1-g[fa])\times \frac{1-f[fa]}{1-f[i]\times P_{i,fa}}\big)\times P_{i,fa}
    \]

    注意去掉当前点贡献时,如果当前点原来就没有贡献,算得的分母是\(0\),所以应当忽略贡献,分母变为\(1\)。

  • 统计答案的时候是一样的道理,两者是"或"的关系,转化为"与"的关系后再取补即可:

    \[ans=\sum_{i=1}^N 1-(1-f[i])\times (1-g[i])
    \]

\(\\\)

\(Code\ (1)\)


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 500010
#define R register
#define gc getchar
using namespace std; int n,tot,hd[N],p[N];
double ans,tmp,f[N],g[N];
struct edge{int to,nxt,p;}e[N<<1]; inline void add(int u,int v,int p){
e[++tot].to=v; e[tot].p=p;
e[tot].nxt=hd[u]; hd[u]=tot;
} inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
} inline void dfs1(int u,int fa){
f[u]=0.01*(100-p[u]);
for(R int i=hd[u],v;i;i=e[i].nxt)
if((v=e[i].to)!=fa){
dfs1(v,u);
f[u]*=(1.0-f[v]*(0.01*e[i].p));
}
f[u]=1.0-f[u];
} inline void dfs2(int u,int fa){
for(R int i=hd[u],v;i;i=e[i].nxt)
if((v=e[i].to)!=fa){
double pf=(1.0-f[v]*(0.01*e[i].p));
if(pf<1e-8) pf=1.0;
g[v]=(1.0-(1.0-g[u])*(1.0-f[u])/pf)*(0.01*e[i].p);
dfs2(v,u);
}
} int main(){
n=rd();
for(R int i=1,u,v,w;i<n;++i){
u=rd(); v=rd(); w=rd();
add(u,v,w); add(v,u,w);
}
for(R int i=1;i<=n;++i) p[i]=rd();
dfs1(1,-1);
dfs2(1,-1);
for(R int i=1;i<=n;++i) ans+=1.0-(1.0-f[i])*(1.0-g[i]);
printf("%.6lf\n",ans);
return 0;
}

\(\\\)

\(Solution\ (2)\)


  • 同样的转化问题二次扫描,但状态都从被点亮变为不被点亮,换个角度再推一遍,设\(f[i]\)表示只考虑当前节点和所有当前节点子树的节点,当前节点不被点亮的概率,设\(g[i]\)表示只考虑除掉当前节点和所有当前节点子树的节点剩下的节点,当前节点不被点亮的概率。

  • 对于\(f[i]\),需要注意的是不能直接借鉴上面的写法,因为转移自子树的\(f\)的定义有变化。一个点不被点亮,当且仅当自己不会被外界直接点亮,也不被子树内的点点亮。不被子树内的点点亮需要分两种情况,子树直接不被点亮,或子树被点亮而边不连通,于是有:

    \[f[i]=(1-P_i)\times \prod_{v\in son[i]}\big(f[v]+(1-f[v])\times(1- P_{i,v})\big)
    \]

  • 对于\(g[i]\),同样需要考虑父节点是否点亮,设父节点不被点亮的概率为\(Q_{fa}\),则有:

    \[g[i]=Q_{fa}+(1-Q_{fa})\times P_{i,fa}
    \]

    对与\(Q_{fa}\)的求法跟上一种方案是一样的,讨论分成\(g\)和\(f\)两部分,有:

    \[Q_{fa}=g[fa]\times\frac{f[fa]}{f[i]+(1-f[i])\times(1-P_{i,fa})}
    \]

  • 可以发现,反过来设计状态所需要处理的式子就容易了很多,对答案有:

    \[ans=\sum_{i=1}^N 1-f[i]\times g[i]
    \]

\(\\\)

\(Code\ (2)\)


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 500010
#define R register
#define gc getchar
using namespace std; double ans,tmp,f[N],g[N];
int n,tot,hd[N],p[N],fp[N];
struct edge{int to,nxt,p;}e[N<<1]; inline void add(int u,int v,int p){
e[++tot].to=v; e[tot].p=p;
e[tot].nxt=hd[u]; hd[u]=tot;
} inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
} inline void dfs1(int u,int fa){
f[u]=0.01*(100-p[u]);
for(R int i=hd[u],v;i;i=e[i].nxt)
if((v=e[i].to)!=fa){
dfs1(v,u); fp[v]=e[i].p;
f[u]*=(f[v]+(1.0-f[v])*(0.01*(100-e[i].p)));
}
} inline void dfs2(int u,int fa){
if(fa==-1) g[u]=1.0;
else{
double pf=g[fa]*(f[fa]/(f[u]+((double)1-f[u])*(0.01*(100-fp[u]))));
g[u]=pf+((double)1-pf)*(0.01*(100-fp[u]));
}
for(R int i=hd[u];i;i=e[i].nxt) if(e[i].to!=fa) dfs2(e[i].to,u);
} int main(){
n=rd();
for(R int i=1,u,v,w;i<n;++i){
u=rd(); v=rd(); w=rd();
add(u,v,w); add(v,u,w);
}
for(R int i=1;i<=n;++i) p[i]=rd();
dfs1(1,-1); dfs2(1,-1);
for(R int i=1;i<=n;++i) ans+=1.0-f[i]*g[i];
printf("%.6lf\n",ans);
return 0;
}

[ SHOI 2014 ] 概率充电器的更多相关文章

  1. [bzoj 3566][SHOI 2014]概率充电器

    传送门 Description SHOI 概率充电器由 n-1 条导线连通了 n 个充电元件.进行充电时,每条导线是否可以导电以概率决定,每一个充电元件自身是否直接进行充电也由概率决定. 随后电能可以 ...

  2. 解题:SHOI 2014 概率充电器

    题面 显然就是在求概率,因为期望乘的全是1....然后就推推推啊 设$fgg[i]$表示这个点父亲没给他充上电的概率,$sgg[i]$表示这个点子树(和它自己)没给他充上电的概率,然后这个点没充上电的 ...

  3. BZOJ 3566: [SHOI2014]概率充电器( 树形dp )

    通过一次dfs求出dp(x)表示节点x考虑了x和x的子树都没成功充电的概率, dp(x) = (1-p[x])π(1 - (1-dp[son])*P(edge(x, son)).然后再dfs一次考虑节 ...

  4. bzoj 3566: [SHOI2014]概率充电器

    Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器:"采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率 ...

  5. [SHOI2014]概率充电器

    Description 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品——概率充电器: “采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决定!SHOI 概率充电器, ...

  6. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  7. [SHOI2014]概率充电器(概率+换根dp)

    著名的电子产品品牌SHOI 刚刚发布了引领世界潮流的下一代电子产品—— 概率充电器: “采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决 定!SHOI 概率充电器,您生活不可或缺的必需品 ...

  8. BZOJ3566: [SHOI2014]概率充电器 树形+概率dp

    3566: [SHOI2014]概率充电器 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1888  Solved: 857[Submit][Stat ...

  9. 洛谷 P4284 [SHOI2014]概率充电器 解题报告

    P4284 [SHOI2014]概率充电器 题目描述 著名的电子产品品牌SHOI 刚刚发布了引领世界潮流的下一代电子产品-- 概率充电器: "采用全新纳米级加工技术,实现元件与导线能否通电完 ...

随机推荐

  1. IDEA下tomcat中web项目乱码,控制台乱码解决指南

    若是由于过滤器,request ,response等原因,不适用. 原文作者:http://www.kafeitu.me/tools/2013/03/26/intellij-deal-chinese- ...

  2. Leetcode 80.删除重复数组的重复项

    删除重复数组的重复项 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间 ...

  3. ZOJ 3201 树形背包问题

    题目大意: 0~n-1号这n个点,每个点有个权值,由无向边形成了一棵树,希望在这棵树上找到一棵长为m的子树使总的权值最小 基本的树形背包问题 令dp[u][j] 表示u号节点对应子树中有j个节点所能得 ...

  4. 救命(洛谷 U4525)

    题目背景 XS中学的校长积劳成疾,最终由于无聊而卧病在沙发.需要药(pi)水(gu)拯救他的生活. 题目描述 现在有n种药水,编号分别为1..n,能拯救校长的药水编号为n 每个药水都可以购买到,但有的 ...

  5. strace oracle

    http://www.itpub.net/thread-1865593-1-1.html

  6. How can I add files to a Jar file? (or add a file to a zip archive)

    https://stackoverflow.com/questions/12239764/how-can-i-add-files-to-a-jar-file M.java class M{ publi ...

  7. 微信公众号H5用户授权

    其实不是很难,总结起来就是: 1.微信公众号管理后台设置redirect_uri. 2.然后发起一个请求去重定向获取code,然后把获取到code之后重定向的URL放在获取code的URL中 3.获取 ...

  8. tableView优化

    ※ tableView优化 概括说:1.使用不透明视图.2.不要重复创建不必要的table cell.3.减少视图的数目.4.不要做多余的绘制工作.5.预渲染图像.6.不要阻塞主线程. 详细说:1.使 ...

  9. LeetCode 500. Keyboard Row (键盘行)

    Given a List of words, return the words that can be typed using letters of alphabet on only one row' ...

  10. LeetCode 172. Factorial Trailing Zeroes (阶乘末尾零的数量)

    Given an integer n, return the number of trailing zeroes in n!. Note: Your solution should be in log ...