555我锅太大了,读错了A的题意(居然还做出来了)导致在A上花了太多的时间QWQ
考虑拆成子问题的话,就是我要求u访问到最深结点的概率,我就先求u的孩子v访问到最深结点的概率。
最简单的叶子结点dp[leaf]=1;
现在考虑从孩子的情况推出父亲的情况。
首先要知道,父亲走哪些孩子可以走到以父亲为根的子树的最深结点。
那么求出每个点的最深深度d[u]是多少,如果d[u]==d[v]+1,说明从v在u通往最深叶子的路上。
也就是说,如果只走一步,u走到v是有可能走到最深的,此时产生部分答案为 o=(u走到v的概率) * 【v走到最深结点的概率(就是dp[v])】
但是,假设现在u走到v1,v2都可以通往最深结点,我像上面这样计算后再求和得到的概率是有问题的。假设我现在可以走2步,可能一次走到v1,一次走到v2,这种情况本来应该只计一次数,像上面这样算就在v1,v2分别计了一次数,算重了。
所以可以求当前父亲走一步,走不到最深结点时的概率,就是1-o,走k步每步都到不了最深结点,就是(1-o)^k
那么走k步,能到最深节点的概率就是1-(1-o)^k。k其实就是当前结点的儿子个数,就是当前结点的度数-1
然后就结束了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e6+7;
const ll mod=1e9+7;
ll du[N];
ll dp[N];
struct Edge{
ll v,nxt;
}e[N];
ll p[N],edn,maxd;
void add(ll u,ll v){
e[++edn]=(Edge){v,p[u]};p[u]=edn;
e[++edn]=(Edge){u,p[v]};p[v]=edn;
}
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;b>>=1;
}
return res;
}
ll d[N],dmax[N];
ll mx;
void dfs(ll u,ll f){
d[u]=1;
for(ll i=p[u];~i;i=e[i].nxt){
ll v=e[i].v;
if(v==f) continue;
dfs(v,u);
d[u]=max(d[v]+1,d[u]);
}
if(du[u]==1) dp[u]=1;
else{
ll o=0;
for(ll i=p[u];~i;i=e[i].nxt){
ll v=e[i].v;
if(v==f) continue;
if(d[u]==d[v]+1){
o+=dp[v]*qpow(du[u]-1,mod-2)%mod;
}
}
o%=mod;//important
dp[u]=1-qpow(1-o+mod,du[u]-1)+mod;
dp[u]%=mod;
}
}
int main() {
ll n;
scanf("%lld",&n);
for(ll i=1;i<=n;i++) p[i]=-1;edn=-1;
for(ll i=1,u,v;i<n;i++){
scanf("%lld%lld",&u,&v);
add(u,v);
du[v]++;du[u]++;
}
if(n==1){
printf("1\n");
return 0;
}
du[1]++;
dfs(1,0);
printf("%lld\n",dp[1]);
}