题目链接:https://nanti.jisuanke.com/t/41392
题目大意:每次dfs随机选择儿子中的一个,选择儿子的个数次,问最终能得到正确的树深度的概率
题目思路:榜好像歪了啊,感觉这题贼水啊...同校大佬在我们9题后过了三分钟就一发过了这题,直接罚时压我们一头自闭啊...他们过了才发现这题结果来不及写了,有点难受,还是前期做太慢+太信任榜没有积极开题..
正着感觉很难,不知道选哪个小伙子,正难则反,直接把不行的小伙子踢掉,剩下的都是我要的小伙子。哪些小伙子肯定是不要的?bingo,就是那些深度不够的叶子,他们这条链不行的概率是百分百,而哪些深度是最深的叶子,他们不行的概率是0,到他们就稳了,所以我们要通过叶子回去。那么怎么回去呢?首先,简化问题,如果只选一次咋搞?肯定有聪明的小伙子说了,1/son[u]*dp[y]加和,意思是1/儿子个数(选择这个孩子的概率)*这个儿子不行的概率,把所有儿子的这个值加和就等于只选一次凉凉的概率,一共选儿子的个数次,那就直接来个k的幂次就美滋滋了,然后(1-dp[1]+MOD)%MOD就是答案了
以下是代码:
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
const ll MAXN = 1e6+5;
const ll MOD = 1e9+7;
vector<ll>v[MAXN];
ll powmod(ll x,ll y){
ll ans=1;
for(;y;y>>=1){
if(y&1)ans=ans*x%MOD;
x=x*x%MOD;
}
return ans;
}
ll n,x,y;
ll dep[MAXN],son[MAXN],maxx;
ll dp[MAXN];
void dfs(ll u,ll fa,ll depp){
ll len=v[u].size();
son[u]=0;
dep[u]=depp;
maxx=max(maxx,depp);
ll x=0;
rep(i,0,len-1){
ll y=v[u][i];
if(y==fa)continue;
son[u]++;
dfs(y,u,depp+1);
}
}
void dfs2(ll u,ll fa){
ll len=v[u].size();
ll temp=0;
rep(i,0,len-1){
ll y=v[u][i];
if(y==fa)continue;
dfs2(y,u);
temp=(temp+powmod(son[u],MOD-2)*dp[y]%MOD)%MOD;
}
temp=powmod(temp,son[u]);
dp[u]=temp;
if(!son[u]){
if(dep[u]==maxx){
dp[u]=0;
}
else dp[u]=1;
}
}
int main()
{
while(~scanf("%lld",&n))
{
memset(dep,0,sizeof(dep));
memset(dp,0,sizeof(dp));
maxx=0;
rep(i,1,n)v[i].clear();
rep(i,1,n-1){
scanf("%lld%lld",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1,-1,1);
dfs2(1,-1);
printf("%lld\n",(1-dp[1]+MOD)%MOD);
}
return 0;
}