• Bzoj3566: [SHOI2014]概率充电器


    题面

    传送门

    Sol

    算出每个点从子树内使它没电的概率和子树外使它没电的概率即可

    注意算子树外使它没电的概率时,父亲转移来要除掉它的贡献,直接除可能有(0)的情况
    可以把每个点的儿子排成一列,求一遍前后缀的积来计算

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int _(5e5 + 5);
    
    IL int Input(){
    	RG int x = 0, z = 1; RG char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    	for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    	return x * z;
    }
    
    double ans, f[_], g[_], tmp[_], tp[_], h[_], p[_];
    int n, cnt, first[_], son[_], len;
    struct Edge{
    	int to, next;
    	double p;
    } edge[_ << 1];
    
    IL void Add(RG int u, RG int v, RG double pi){
    	edge[cnt] = (Edge){v, first[u], pi}, first[u] = cnt++;
    	edge[cnt] = (Edge){u, first[v], pi}, first[v] = cnt++;
    }
    
    IL void Dfs1(RG int u, RG int ff){
    	for(RG int e = first[u]; e != -1; e = edge[e].next){
    		RG int v = edge[e].to;
    		if(v == ff) continue;
    		Dfs1(v, u);
    		tp[v] = edge[e].p;
    		h[v] = f[v] + (1.0 - f[v]) * (1.0 - tp[v]);
    		f[u] *= h[v];
    	}
    }
    
    IL void Dfs2(RG int u, RG int ff){
    	len = 0;
    	for(RG int e = first[u]; e != -1; e = edge[e].next)
    		if(edge[e].to != ff) son[++len] = edge[e].to;
    	RG double t = 1.0, ft = g[u] * (1.0 - p[u]); tmp[len + 1] = 1.0;
    	for(RG int i = len; i; --i) tmp[i] = tmp[i + 1] * h[son[i]];
    	for(RG int i = 1; i <= len; ++i){
    		RG double pi = t * ft * tmp[i + 1];
    		g[son[i]] = pi + (1.0 - pi) * (1.0 - tp[son[i]]);
    		t *= h[son[i]];
    	}
    	for(RG int e = first[u]; e != -1; e = edge[e].next)
    		if(edge[e].to != ff) Dfs2(edge[e].to, u);
    }
    
    int main(RG int argc, RG char *argv[]){
    	Fill(first, -1);
    	n = Input();
    	for(RG int i = 1; i < n; ++i){
    		RG int u = Input(), v = Input(), pi = Input();
    		Add(u, v, 0.01 * pi);
    	}
    	for(RG int i = 1; i <= n; ++i) p[i] = 0.01 * Input(), f[i] = 1.0 - p[i];
    	Dfs1(1, 0), g[1] = 1, Dfs2(1, 0);
    	for(RG int i = 1; i <= n; ++i) ans += 1.0 - f[i] * g[i];
    	printf("%.6lf
    ", ans);
    	return 0;
    }
    
    
  • 相关阅读:
    .NET面试题解析(07)-多线程编程与线程同步
    .NET面试题解析(06)-GC与内存管理
    .NET面试题解析(05)-常量、字段、属性、特性与委托
    .NET面试题解析(04)-类型、方法与继承
    .NET面试题解析(03)-string与字符串操作
    .NET面试题解析(02)-拆箱与装箱
    .NET面试题解析(01)-值类型与引用类型
    StackExchange.Redis使用配置
    X--名称空间详解
    深入浅出话资源
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8659762.html
Copyright © 2020-2023  润新知