• CF1060F Shrinking Tree


    考虑枚举每个点来计算答案,枚举到一个点时,将该点看作是树的根。设 (f_{x,i}) 为在 (x) 的子树内进行删边,只考虑后 (i) 条边的编号分配,其余边任意分配,且根节点编号最后仍为 (x) 的概率之和。得 (x) 的最终答案为 (frac{f_{x,n-1}}{(n-1)!})

    考虑合并子树,将 (x) 的儿子 (y) 合并到当前子树中,发现需要给 (y) 加上一条到 (x) 的边,用新子树的 (DP) 值来转移。设新的 (DP) 值为 (g_i),其定义和 (f_{x,i}) 相同。

    考虑如何计算 (g_i),枚举 ((x,y)) 这条边在倒数第 (j) 步被删掉。当 (i geqslant j) 时,这里要求删掉 ((x,y)) 时必须保留 (x),有 (frac{1}{2}) 的概率,之前的边的选择是任意的,之后必须保留 (x),这里删去了 ((x,y)),保留 (y) 和保留 (x) 等价,因此将 (frac{1}{2}f_{y,j-1}) 贡献到 (g_i)。当 (i<j) 时,((x,y)) 这条边不用考虑编号分配,因此将 (f_{y,i}) 贡献到 (g_i)

    合并子树时就是将 (f_{x,i}g_jinom{i+j}{i}inom{siz_x-1-i+siz_y-j}{siz_x-1-i}) 贡献到 (f_{x,i+j})

    #include<bits/stdc++.h>
    #define maxn 110
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n;
    int siz[maxn];
    double fac[maxn],f[maxn][maxn],g[maxn];
    struct edge
    {
        int to,nxt;
        edge(int a=0,int b=0)
        {
            to=a,nxt=b;
        }
    }e[maxn];
    int head[maxn],edge_cnt;
    void add(int from,int to)
    {
        e[++edge_cnt]=edge(to,head[from]),head[from]=edge_cnt;
    }
    double C(int n,int m)
    {
        return fac[n]/fac[m]/fac[n-m];
    }
    void dfs(int x,int fa)
    {
        f[x][0]=siz[x]=1;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(y==fa) continue;
            dfs(y,x);
            for(int j=0;j<=siz[y];++j)
                for(int k=1;k<=siz[y];++k)
                    f[0][j]+=k<=j?f[y][k-1]/2:f[y][j];
            for(int j=siz[x]-1;j>=0;--j)
                for(int k=siz[y];k>=0;--k)
                    g[j+k]+=f[x][j]*f[0][k]*C(j+k,j)*C(siz[x]-1-j+siz[y]-k,siz[x]-1-j);
            siz[x]+=siz[y];
            for(int i=0;i<siz[x];++i) f[x][i]=g[i];
            memset(g,0,sizeof(g)),memset(f[0],0,sizeof(f[0]));
        }
    }
    int main()
    {
        read(n);
        for(int i=1;i<n;++i)
        {
            int x,y;
            read(x),read(y);
            add(x,y),add(y,x);
        }
        fac[0]=1;
        for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i;
        for(int i=1;i<=n;++i)
        {
            memset(f,0,sizeof(f)),dfs(i,0);
            printf("%.10lf
    ",f[i][n-1]/fac[n-1]);
        }
        return 0;
    }
    
  • 相关阅读:
    2019计蒜之道初赛第三场题解
    牛客小白月赛14 :部分题目总结
    CF-558:部分题目总结
    浙江省第十六届大学生ACM程序设计竞赛部分题解
    浙江省高职院校联合训练(一)
    CF-544:部分题目总结
    CF-552E-Two Teams
    CF-551:部分题目总结
    freemarker使用map替换字符串中的值
    freemarker使用map替换ftl中相关值
  • 原文地址:https://www.cnblogs.com/lhm-/p/14332256.html
Copyright © 2020-2023  润新知