• CF1060F Shrinking Tree


    CF1060F Shrinking Tree 

    DP好题

    %%ywy

    肯定考虑在压缩中找到不变的关系。

    n很小,不妨枚举每个点成为最后编号的情况,并且把这个点rt作为根

    其实概率是:p/(n-1)!*(1/2)^k这里的p是所有缩边的排列中,和rt合并有k次的方案数。

    我们只计算p*(1/2)^k部分,最后统一除以(n-1)!

    基础的想法:

    f[x][k]x为根的子树,和x合并k次的方案数,但是由于不知道和父亲的边什么时候缩,无法转移

    直接记录到父亲?g[x][k],和x的fa合并k次方案数?其实还不能转移。

    问题就是在于和父亲的边e不知道什么时候缩

    再考虑到,可能当父亲是rt的时候特殊考虑,

    如下定义状态:

    dp[x][k]x为根的子树的边序列,当x变成rt的时候,还有k条边没有合并,最终合并成一个rt的大点的概率和

    g[x][k]x为根的子树+x到fa的e的边的序列g,当fa变成rt的时候,g总共还有k条边没有合并,最终合并成一个rt的大点的概率和

    这种奇怪的设法,有点对未来承诺的意思,而且是直接加入了状态的定义里,并没有用数组某一维记录。

    并且有一个明显的划分点:x或者fa变成rt,这样便于统计1/2概率的额外限制

    至于e的合并,我们可以在g中考虑到。

    我们把之前的合并k次,直接在dp值中进行计算即可。

    e在合并的时候,x有没有变成rt,再利用之前的dp[son],两种情况讨论,可以求出g[son]

    再用g[son]们,背包进行合并。

    只要保证分配的新序列中,x变成rt之前的操作都在x变成rt之前。分别组合数分配即可。

    ans[rt]=dp[rt][n-1]

    O(n^4)

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    namespace Modulo{
    const int mod=998244353;
    int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
    void inc(int &x,int y){x=ad(x,y);}
    int mul(int x,int y){return (ll)x*y%mod;}
    void inc2(int &x,int y){x=mul(x,y);}
    int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
    }
    //using namespace Modulo;
    namespace Miracle{
    const int N=55;
    double dp[N][N],g[N][N],tmp[N];
    double C[N][N];
    int n;
    double ans[N];
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int sz[N];
    void dfs(int x,int fa){
        sz[x]=1;
        dp[x][0]=1.00;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            dfs(y,x);
            for(reg j=0;j<=sz[y];++j){
                g[y][j]=(double)(sz[y]-j)*dp[y][j];
                for(reg k=0;k<j;++k){
                    g[y][j]+=(double)0.5*dp[y][k];
                }
            }
            memset(tmp,0,sizeof tmp);
            for(reg k=0;k<sz[x];++k){
                for(reg j=0;j<=sz[y];++j){
                    tmp[k+j]+=C[sz[x]+sz[y]-k-j-1][sz[x]-1-k]*C[k+j][k]*dp[x][k]*g[y][j];
                }
            }
            sz[x]+=sz[y];
            for(reg k=0;k<sz[x];++k) dp[x][k]=tmp[k];
        }
    }
    int main(){
        rd(n);int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);add(x,y);add(y,x);
        }
        C[0][0]=1;
        for(reg i=1;i<=n;++i){
            C[i][0]=1;
            for(reg j=1;j<=i;++j){
                C[i][j]=C[i-1][j-1]+C[i-1][j];
            }
        }
        for(reg i=1;i<=n;++i){
            memset(dp,0,sizeof dp);
            memset(g,0,sizeof g);
            dfs(i,0);
            ans[i]=dp[i][n-1];
        }
        double jie=1;
        for(reg i=2;i<n;++i) jie*=i;
        for(reg i=1;i<=n;++i){
            printf("%.10lf
    ",ans[i]/jie);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */

    考虑x是不是rt,要进行讨论的。考虑e什么时候合并,也是要讨论的。

    x是不是rt就成了分界点。e什么时候合并也是关键点,这样才对son的子树内序列做出了限制。也才能用上dp[son]转移。

    所以状态就直接记录还剩下多少个边没有合并,这些边都要注意是否有1/2的概率限制。而且还可知道之前放入了多少边,有助于组合数分配转移。

  • 相关阅读:
    魔理沙的烟火制造
    【数位DP】恨7不成妻
    Happy Equation
    实验4
    Max answer(The Preliminary Contest for ICPC China Nanchang National Invitational)
    Next K Permutation
    Hubtown(最大流)
    Compass Card Sales(模拟)
    Ghostbusters(并查集,最小生成树)
    游览器兼容性笔记
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10940536.html
Copyright © 2020-2023  润新知