The Preliminary Contest for ICPC Asia Xuzhou 2019 J Random Access Iterator (树形DP)

每次循环向下寻找孩子时,随机选取一个孩子,设dp[u]为从u出发,不能得出正确答案的概率,则从u出发,走一次的情况下不能得出正确答案的概率是 P = (dp[v1]+dp[v2]+dp[v3]+……dp[vk]) / cnt_son[u] ,则从u出发,要走cnt_son[u]次,那么dp[u]=P^cnt_con[u]
dp的意义也可以改成能得出正确答案的概率,下面的式子稍微改改就行了
为了避免除法的精度问题,num/k %mod,它等于 num * ni %mod ,ni等于k在模mod意义下的逆元。

#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int maxn=1e6+10;

long long N;
vector<long long> vc[maxn];
long long deep[maxn],dp[maxn],MaxDeep=-1,son[maxn];

void dfs(long long u,long long pre)
{
    deep[u]=deep[pre]+1;
    MaxDeep=max(MaxDeep,deep[u]);
    int size=vc[u].size();
    for (int i=0;i<size;i++) {
        if (vc[u][i]!=pre) {
            son[u]++;
            dfs(vc[u][i],u);
        }
    }
}

long long quick_pow(long long base,long long p)
{
    long long ans=1;
    while (p) {
        if (p&1) {
            ans=ans*base%mod;
        }
        base=base*base%mod;
        p>>=1;
    }
    return ans;
}

void dfs2(long long u,long long pre)
{
    if (!son[u]) {
        if (deep[u]==MaxDeep) {
            dp[u]=0;
        }
        else {
            dp[u]=1;
        }
        return ;
    }
    int size=vc[u].size();
    long long tmp=0,ni=quick_pow(son[u],mod-2);
    for (int i=0;i<size;i++) {
        if (vc[u][i]==pre) continue;
        dfs2(vc[u][i],u);
        tmp=(tmp+(dp[vc[u][i]]*ni)%mod)%mod;
    }
    dp[u]=quick_pow(tmp,son[u]);
}

int main()
{
    scanf("%lld",&N);
    long long u,v;
    for (int i=1;i<N;i++) {
        scanf("%lld%lld",&u,&v);
        vc[u].push_back(v);
        vc[v].push_back(u);
    }
    dfs(1,0);
    dfs2(1,0);
    printf("%lld
",(1-dp[1]+mod)%mod);
    // for (int i=0;i<=N;i++) {
    //     printf("%lld %lld
",deep[i],son[i]);
    // }
    // printf("%lld
",MaxDeep);
    return 0;
}
原文地址:https://www.cnblogs.com/xyqxyq/p/12328862.html