#3192. Smuggling Marbles

題目描述

lre有一棵 n+1n+1 個節點的樹, 00 號點是樹根,第 ii 個點的父親是 aia_i

每個點上都可以放一個彈珠或不放。之後每一回合,lre都會把所有彈珠移動到它們所在的節點的父親節點。

若一個節點上有大於 11 個彈珠,它們會一起被lre打爆消失。原來在 00 號節點上的彈珠則會被lre收集起來。

lre覺得這可以出一道題,就問你所有放置彈珠的方案操作完(樹上沒有彈珠)之後可收集到的彈珠的數目之和 (mod  109+7)(mod~~10^9+7)

題解

考慮到同一深度的貢獻爲 0/10/1 ,然後將方案數轉化成概率好像更好計算,所以考慮暴力 dp\text{dp}f[i][j][0/1]f[i][j][0/1] 表示 ii 子樹內,距離 ii 深度爲 jj 的貢獻爲 0/10/1 的概率,轉移的話 f[i][0][0/1]=12,f[i][j][1]=vf[v][j1][1]vvf[v][j1][0],f[i][j][0]=1f[i][j][1]f[i][0][0/1]=\frac{1}{2},f[i][j][1]=\sum_{v} f[v][j-1][1] \prod_{v' \ne v} f[v'][j-1][0],f[i][j][0]=1-f[i][j][1] 。然後這樣是 O(n2)O(n^2) 的。考慮優化,如果我們把深度最深的兒子的 dp\text{dp} 值直接繼承到 ii ,然後剩下的暴力合併上去的話就是 O(n)O(n) 的效率了。具體證明的話就是每個點對答案的貢獻最多隻有在某一次會被暴力合併。(by 蘇ak:這和長鏈剖分是一樣的)。

代碼

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5,P=1e9+7;
int n,hd[N],V[N],nx[N],t,f[N],p[N],d[N],id[N];
struct O{int x,y;};vector<O>g[N];
int K(int x,int y){
	int z=1;
	for (;y;y>>=1,x=1ll*x*x%P)
		if (y&1) z=1ll*z*x%P;
	return z;
}
void add(int u,int v){
	nx[++t]=hd[u];V[hd[u]=t]=v;
}
void upd(int x,int u){
	for (int i=1;i<=x;i++)
		p[i]=1ll*g[id[u]][d[u]-i].x*p[i]%P;
}
void cal(int x,int u){
	for (int i=1;i<=x;i++)
		(f[i]+=1ll*K(g[id[u]][d[u]-i].x,P-2)*p[i]%P*g[id[u]][d[u]-i].y%P)%=P;
}
void dfs(int u){
	int son=n+1,x=0;
	for (int v,i=hd[u];i;i=nx[i]){
		dfs(v=V[i]);
		if (d[v]>d[son]) son=v;
	}
	if (son>n) id[u]=++t,d[u]=1;
	else{
		id[u]=id[son];d[u]=d[son]+1;
		for (int i=hd[u];i;i=nx[i])
			if (V[i]!=son) x=max(d[V[i]],x);
		for (int i=1;i<=x;i++) p[i]=1,f[i]=0;
		for (int i=hd[u];i;i=nx[i]){
			if (V[i]==son) upd(x,son);
			else upd(d[V[i]],V[i]);
		}
		for (int i=hd[u];i;i=nx[i]){
			if (V[i]==son) cal(x,son);
			else cal(d[V[i]],V[i]);
		}
		for (int i=1;i<=x;i++)
			g[id[u]][d[son]-i].y=f[i],
			g[id[u]][d[son]-i].x=(P+1-f[i])%P;
	}
	g[id[u]].push_back((O){(P+1)>>1,(P+1)>>1});
}
int main(){
	cin>>n;
	for (int i=1,x;i<=n;i++)
		scanf("%d",&x),add(x,i);
	dfs(t=0);int x=0;
	for (int i=0;i<d[0];i++)
		(x+=g[id[0]][i].y)%=P;
	cout<<1ll*x*K(2,n+1)%P<<endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章