树上随机游走与树上高斯消元

题目大意:

给定一棵树,求出一对起点和终点,使得从起点随机游走,到终点停下的期望步数最多,输出这个期望步数

solution:

其实不难

树形 \(dp\)

首先,另 \(f[x]\) 表示从 \(x\) 点走到他父亲的期望步数

它有可能先走到某个儿子里,然后再回来,也有可能直接走到它的父亲

因此:

\[f[x]=\frac{1}{|son[x]|+1}+\sum_{u ∈ son[x]}\frac{f[u]+f[x]+1}{|son[x]|+1} \]

有:

\[f[x]=\frac{1}{|son[x]|+1}+f[x]*\sum_{u ∈ son[x]}\frac{1}{|son[x]|+1}+\sum_{u ∈ son[x]}\frac{f[u]+1}{|son[x]|+1} \]

\[f[x]=\frac{1}{|son[x]|+1}+f[x]*\frac{|son[x]|}{|son[x]|+1}+\sum_{u ∈ son[x]}\frac{f[u]+1}{|son[x]|+1} \]

\[\frac{f[x]}{|son[x]|+1}=\frac{1}{|son[x]|+1}+\sum_{u ∈ son[x]}\frac{f[u]+1}{|son[x]|+1} \]

最后得到:

\[f[x]=|siz[x]|+1+\sum_{u ∈ son[x]}f[u] \]

也就是说你把它子树内所有点的度数加起来就可以了

然后,另 \(g[x]\) 表示从 \(x\) 的父亲走到 \(x\) 的期望步数

从它父亲出发,有可能先走到其它的某个子树中再回来,也有可能走到它父亲的父亲再回来,也有可能直接走到 \(x\)

因此:

\[g[x]=\frac{g[x]+g[fa[x]]+1}{|son[x]|+1}+\frac{1}{|son[x]|+1}+\sum_{u ∈ son[fa[x]],u!=x}\frac{g[x]+f[u]+1}{|son[x]|+1} \]

有:

\[g[x]=g[x]*\frac{|son[x]|}{|son[x]|+1}+\frac{g[fa[x]]+1}{|son[x]|+1}+\frac{1}{|son[x]|+1}+\sum_{u ∈ son[fa[x]],u!=x}\frac{f[u]+1}{|son[x]|+1} \]

\[\frac{g[x]}{|son[x]|+1}=\frac{g[fa[x]]+1}{|son[x]|+1}+\frac{1}{|son[x]|+1}+\sum_{u ∈ son[fa[x]],u!=x}\frac{f[u]+1}{|son[x]|+1} \]

\[g[x]=(g[fa[x]]+1)+1+\sum_{u ∈ son[fa[x]],u!=x}(f[u]+1) \]

\[g[x]=(g[fa[x]]+1)+1+(\sum_{u ∈ son[fa[x]],u!=x}f[u])+(|son[x]|-1) \]

\[g[x]=g[fa[x]]+(|son[x]|+1+\sum_{u ∈ son[fa[x]],u!=x}f[u]) \]

最后得到:

\[g[x]=g[fa[x]]+f[fa[x]]-f[x] \]

都很简洁,两次树形 \(dp\) 就可以求出

知道了每条边向上走和向下走的期望步数,第三次树形 \(dp\) 求出树的带权直径即可

#include <bits/stdc++.h>
using namespace std;
int n;
int ver[200005],ne[200005],head[200005],cnt;
inline void link(int x,int y){
	ver[++cnt]=y;
	ne[cnt]=head[x];
	head[x]=cnt;
}
int siz[100005];
int f[100005],g[100005];
void dfs1(int x,int fi){
	f[x]=siz[x];
	for(int i=head[x];i;i=ne[i]){
		int u=ver[i];
		if(u==fi)continue;
		dfs1(u,x);
		f[x]+=f[u];
	}
}
void dfs2(int x,int fi){
	for(int i=head[x];i;i=ne[i]){
		int u=ver[i];
		if(u==fi)continue;
		g[u]=f[x]-f[u]+g[x];
		dfs2(u,x);
	}
}
int dp[2][100005],ans;
void dfs3(int x,int fi){
	for(int i=head[x];i;i=ne[i]){
		int u=ver[i];
		if(u==fi)continue;
		dfs3(u,x);
		ans=max(ans,dp[0][x]+dp[1][u]+f[u]);
		ans=max(ans,dp[1][x]+dp[0][u]+g[u]);
		dp[0][x]=max(dp[0][x],dp[0][u]+g[u]);
		dp[1][x]=max(dp[1][x],dp[1][u]+f[u]);
 }
}
int main(){
	freopen("rw.in","r",stdin);
	freopen("rw.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int x,y;scanf("%d%d",&x,&y);
		link(x,y);link(y,x);
		siz[x]++;siz[y]++;
	}
	dfs1(1,1);
	dfs2(1,1);
	dfs3(1,1);
	printf("%d.00000",ans);

	return 0;
}


[PKUWC2018]随机游走

首先用 \(min-max\) 容斥将题目转化为求从根到达集合内任意一点的期望步数

\[\begin{cases} dp[x,S]=(dp[fa,S]+1)*\frac {1}{deg[x]}+\sum_{u\in son[x]}(dp[u,S]+1)*\frac {1}{deg[x]} \ (x \notin S)\\ dp[x,S]=0 \ (x \in S)\\ \end{cases} \]

只考虑 \(x\notin S\) 的情况:

设:

\[dp[x]=A_x*dp[fa]+B_x \]

带入原式中:

\[dp[x]=(dp[fa]+1)*\frac {1}{deg[x]}+\sum_{u\in son[x]}(dp[u]+1)*\frac {1}{deg[x]+1} \]

\[dp[x]=\frac {1}{deg[x]}*(dp[fa]+\sum_{u\in son[x]}dp[u])+1 \]

\[dp[x]=\frac {1}{deg[x]}*(dp[fa]+\sum_{u\in son[x]}A_u*dp[x]+\sum_{u\in son[x]} B_u)+1 \]

\[dp[x]*deg[x]=dp[fa]+\sum_{u\in son[x]}A_u*dp[x]+\sum_{u\in son[x]} B_u+deg[x] \]

\[(deg[x]-\sum_{u\in son[x]}A_u)*dp[x]=dp[fa]+\sum_{u\in son[x]} B_u+deg[x] \]

\[dp[x]=\frac {1}{deg[x]-\sum_{u\in son[x]}}*dp[fa]+\frac{\sum_{u\in son[x]} B_u+deg[x]}{deg[x]-\sum_{u\in son[x]}} \]

因此,解得:

\[A=\frac {1}{deg[x]-\sum_{u\in son[x]}} \]

\[B=\frac{\sum_{u\in son[x]} B_u+deg[x]}{deg[x]-\sum_{u\in son[x]}} \]

由于根没有父亲,那么对于集合 \(S\),有:

\[ans[S]=dp[rt,S]=B_{rt} \]

对每个集合进行一次树形 \(dp\) ,再来一次 \(fwt\) 即可求出所有集合的答案

#include<bits/stdc++.h>
using namespace std;
int n,q,rt;
int ver[45],ne[45],head[45],tot,deg[45];
inline void link(int x,int y){
	ver[++tot]=y;
	ne[tot]=head[x];
	head[x]=tot;deg[y]++;
}
long long a[21],b[21];
const long long md=998244353;
inline long long pwr(long long x,long long y){
	long long res=1;
	while(y){
		if(y&1)res=res*x%md;
		x=x*x%md;y>>=1;
	}return res;
}
void dfs(int x,int fi,int S){
	if((S>>(x-1))&1)return ;
	long long tota=0,totb=0;
	for(int i=head[x];i;i=ne[i]){
		int u=ver[i];
		if(u==fi)continue;
		dfs(u,x,S);
		tota=(tota+a[u])%md;totb=(totb+b[u])%md;
	}
	a[x]=pwr(deg[x]-tota,md-2);
	b[x]=(deg[x]+totb)%md*a[x]%md;
}
long long dp[1<<18];
int cnt[1<<18];
int main(){
	scanf("%d%d%d",&n,&q,&rt);
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		link(x,y);link(y,x);
	}//puts("111");
	for(int s=1;s<(1<<n);s++){
		cnt[s]=cnt[s>>1]+(s&1);
		for(int i=1;i<=n;i++)a[i]=b[i]=0;
		dfs(rt,rt,s);dp[s]=(cnt[s]&1?1:-1)*b[rt];
	}//puts("222");
	for(int i=0;i<n;i++){
    	for(int s=0;s<(1<<n);s++){
			if((s>>i)&1)continue;
			dp[s|(1<<i)]=(dp[s|(1<<i)]+dp[s])%md;
		}
	}
	while(q--){
		int k,s=0;
		scanf("%d",&k);
		while(k--){
			int x;scanf("%d",&x);
			s|=(1<<(x-1));
		}printf("%lld\n",(dp[s]+md)%md);
	}

	return 0;
}


上一篇:splay


下一篇:【ybt高效进阶 21162】双面扑克(图论模型)(线段树)(并查集)