zoukankan      html  css  js  c++  java
  • P4284 [SHOI2014]概率充电器

    P4284 [SHOI2014]概率充电器


    今天上课讲到的题orz,第一次做这种上下搞两次dp的题。

    g[i]表示i的子树(包括i)给i充电的概率。

    f[i]表示i的父亲给i充电的概率。

    g[]可以快速求出来。h[i]表示i对i父亲的贡献,则

    (h_i=g_i+(1-g_i)(1-w(i,fa_i)))

    (g_i=(1-q_i)Pi_{j=son}h_j)

    (w(i,fa_i))(i)(fa_i)之间路径的长度。

    但是f[]就不好求了= =

    上面已经求出了f[y],要求f[x]。f[x]需要计算除了x的子树之外的所有点。

    可以把这些点分成两部分:绿色和紫色部分

    紫色部分就是f[y],但绿色呢?

    回去看一眼:(g_y=(1-q_y)Pi_{j=son}h_j)

    所以只需要除掉(h_x)就星了。

    (t=frac{g_yf_y}{h_x})

    (f_x=t+(1-t)(1-w(x,y)))

    注意t不是(f_x),t是去掉x子树后y通电的概率,可参照h的求法


    上述方法可获得95分的好成绩。

    因为(t=frac{g_yf_y}{h_x}),如果遇到0就GG了。。。

    观察一下,(h_x=0)的话,t实际是0(因为上面一定会通电下来??

    然后写完了= =

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cctype>
    using namespace std;
    typedef int mmp;
    #define vd void
    #define rg register
    #define il inline
    #define sta static
    il int gi(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    const int maxn=500001;
    int id,fir[maxn],nxt[maxn<<1],dis[maxn<<1],w[maxn<<1];
    int p[maxn];
    il vd link(int x,int y,int z){nxt[++id]=fir[x],fir[x]=id,dis[id]=y,w[id]=z;}
    double f[maxn],g[maxn],h[maxn];
    il vd dp(int x,int fa=-1){
        g[x]=1-p[x]*.01;
        for(rg int i=fir[x];i;i=nxt[i]){
            if(fa==dis[i])continue;
            dp(dis[i],x);
            h[dis[i]]=g[dis[i]]+(1-g[dis[i]])*(1-w[i]*.01);
            g[x]*=h[dis[i]];
        }
    }
    il vd dp2(int x,int fa=-1){
        for(rg int i=fir[x];i;i=nxt[i]){
            if(fa==dis[i])continue;
            double t=(h[dis[i]]<1e-6)?0:g[x]*f[x]/h[dis[i]];
            f[dis[i]]=t+(1-t)*(1-w[i]*.01);
            dp2(dis[i],x);
        }
    }
    mmp main(){
    // 	freopen("4284.in","r",stdin);
    // 	freopen("4284.out","w",stdout);
        int n=gi();
        for(rg int i=1;i<n;++i){
            sta int a,b,p;
            a=gi(),b=gi(),p=gi();
            link(a,b,p),link(b,a,p);
        }
        for(rg int i=1;i<=n;++i)p[i]=gi();
        dp(1);f[1]=1;dp2(1);
        double ans=0;
        for(rg int i=1;i<=n;++i)ans+=1-f[i]*g[i];
        printf("%.6lf
    ",ans);
    // 	for(rg int i=1;i<=n;++i)printf("%.6lf ",f[i]);puts("");
    // 	for(rg int i=1;i<=n;++i)printf("%.6lf ",g[i]);puts("");
    // 	for(rg int i=1;i<=n;++i)printf("%.6lf ",h[i]);puts("");
        return 0;
    }
    
  • 相关阅读:
    BZOJ3779: 重组病毒
    BZOJ3112 [ZJOI2013]防守战线
    BZOJ4011 [HNOI2015]落忆枫音
    BZOJ2726 [SDOI2012]任务安排
    BZOJ1492 [NOI2007]货币兑换
    BZOJ1597 [USACO2008]土地购买
    BZOJ3611 [HEOI2014]大工程
    BZOJ3991 [SDOI2015]寻宝游戏
    BZOJ3675 [APIO2014]序列分割
    BZOJ1010 [HNOI2008]玩具装箱
  • 原文地址:https://www.cnblogs.com/xzz_233/p/8658612.html
Copyright © 2011-2022 走看看