[計蒜客]2019 ICPC 徐州網絡賽 J(樹形dp)

傳送門:https://nanti.jisuanke.com/t/41392

題意:

從樹的根節點開始dfs(1,1),假設當前節點u的子結點有k個,則遞歸調用dfs(v,d+1)k次,每次的v都隨機從u的k個子結點中選取。問成功找到整棵樹的深度的概率是多少?

分析:

顯然,這是一道樹形dp題,只要推出轉移方程即可。比賽時沒能推出正確的轉移方程,後來看了別人的題解就懂了。

轉移方程:令s=\sum{dp(v),v爲當前結點u的子結點,則dfs(u)=(s/k)^{k}

其實就是統計不能到達最深處的概率p,答案爲1-p。

代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int P=1e9+7;
const int maxn=1e6+10;
vector<int> G[maxn];
int n,H=1;
ll qsm(ll a,ll b){
	ll res=1;
	while(b){
		if(b&1)
			res=res*a%P;
		a=a*a%P;
		b>>=1;
	}
	return res;
}
ll inv(ll k){
	return qsm(k,P-2);
}
void read(){
	int u,v;
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
}
void find(int u,int p,int d){
	H = max(H,d);
    for(int v=0;v<G[u].size();v++)
    	if(G[u][v]!=p) 
			find(G[u][v],u,d+1);
}
ll dfs(int u,int p,int d){
	ll dp=0,k=0;
	for(int i=0;i<G[u].size();i++)
		if(G[u][i]!=p)
			dp+=dfs(G[u][i],u,d+1),k++;
	if(k)
		return qsm(dp*inv(k)%P,k);
	else
		return d!=H?1:0;
}
int main(){
	read();
	find(1,0,1);
	printf("%lld\n",(1+P-dfs(1,0,1))%P);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章