2019ICPC徐州網絡賽J. Random Access Iterator

題意:

給你一棵以1爲根的樹,以如下方式遍歷這個樹來求樹的高度(根節點與葉子節點之間的最大距離)
在這裏插入圖片描述
從根節點出發,隨機遍歷每個子樹,問能夠計算出樹的高度的概率是多少,
要求結果對1000000007取模(ainv(b)a * inv(b),其中a爲分子,b爲分母)

分析:

樹形DP與概率相結合,和之前南京網絡賽的題目方向相似
dp[i]:表示第i個節點爲根來能夠求出當前子樹的概率爲多少
注意到:

對於葉子節點且不是與根節點距離最大的葉子節點(如下圖中的2),dp值爲0
對於與根節點距離最大葉子節點(如下圖中的3、4),dp值爲1

在這裏插入圖片描述

我們考慮dp方程的轉移,以1節點爲例子
我們考慮無法求出爭取高度的概率爲P,那麼求出正確高度的概率爲1 - P
對於1節點我們有三次選擇方式,每次等概率選擇所有的點,那麼有以下幾種排列方式

排列方式 概率
②② (1dp[2])(1dp[2])(1 - dp[2])*(1 - dp[2])
②③ (1dp[2])(1dp[3])(1 - dp[2])*(1 - dp[3])
③② (1dp[3])(1dp[2])(1 - dp[3])*(1 - dp[2])
③③ (1dp[3])(1dp[3])(1 - dp[3])*(1 - dp[3])

對右邊式子求和整理,得[(1dp[2])+(1dp[3])]2[(1 - dp[2]) + (1 - dp[3])]^2
又因爲每種情況的概率相同我們可以得到
dp[1]=[(1dp[2])+(1dp[3])]2122dp[1] = [(1 - dp[2]) + (1 - dp[3])]^2 * {\frac{1}{2 ^ 2}}
依次類推我們得到dp的狀態轉移
dp[i]={0,1,(1dp[k])k(1k)k(kidp[i]=\left\{ \begin{aligned} & \text0,葉子節點且不是與根節點距離最大的葉子節點 \\ & \text1,與根節點距離最大的葉子節點 \\ & ({\sum{1-dp[k]}})^k*({\frac{1}{k}})^k \text (k爲i的子節點),其他 \end{aligned} \right.
其中對於取模問題,我們每次都將算出來的分數用逆元的方式化爲整數即可

代碼:

/*************************************************************************
	> File Name: 2019_Xuzhou_J.cpp
	> Author: z472421519
	> Mail: 
	> Created Time: 2019年09月07日 星期六 15時39分03秒
 ************************************************************************/

#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#define MAXN 1000003
#define ll long long
const ll mod = 1e9 + 7;
using namespace std;

//double AXN],ans;
int dep[MAXN],son[MAXN],g[MAXN],edgesize,res;
struct edges{
    int f,t;
    void var(int a,int b)
    {
        f = a;
        t = b;
    }
}edges[MAXN * 2];
void addedge(int f,int t)
{
    edges[++edgesize].var(g[f],t);
    g[f] = edgesize;
}
void dfs(int now,int d)
{
    res = max(d,res);
    dep[now] = d;
    son[now] = 0;
    for(int i = g[now];i != -1;i = edges[i].f)
    {
        if(dep[edges[i].t])
            continue;
        son[now]++;
        dfs(edges[i].t,d + 1);
    }
}
/*
struct node
{
    int a,b;
};*/
ll quick_pow(ll a,ll n)
{
    ll res = 1;
    while(n)
    {
        if(n & 1)
            res = (res * a) % mod;
        a = (a * a) % mod;
        n >>= 1;
    }
    return res;
}
ll inv(ll a)
{
    return quick_pow(a,mod - 2);
}
ll dfs_dp(int now)
{
    //printf("%d %lf\n",now,dp[now]);
    if(dep[now] == res)
    {
        return 1;
    }
    if(son[now] == 0)
        return 0;
    /*
    node t,T;
    t.a = 0;
    t.b = 0;
    */
    ll t = 0,T = 0;
    for(int i = g[now];i != -1;i = edges[i].f)
    {
        if(dep[edges[i].t] < dep[now])
            continue;
        //if(t.b == 0)
        //dp[edges[i].t] = dp[now] * (2.0 * son[now] - 1) / (son[now] * son[now]);
        T = dfs_dp(edges[i].t);
        T = (1 - T + mod) % mod;
        t = (t + T) % mod;
    }
    t = quick_pow(t,son[now]);
    ll res = quick_pow(inv(son[now]),son[now]);
    t = t * res % mod;
    res = (1 - t + mod) % mod;
    //printf("%d %lld\n",now,res);
    return res;
}
int main()
{
    int n;
    //printf("%lld %lld\n",(1 - 3 * inv(4) + mod) % mod,1 * inv(4) % mod);
    scanf("%d",&n);
    res = 0;
    memset(g,-1,sizeof(g));
    for(int i = 1;i < n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1,1);
    //printf("%d\n",res);
    //node t;
    ll t = dfs_dp(1);
    printf("%lld\n",t);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章