专栏文章

题解:CF2028E Alice's Adventures in the Rabbit Hole

CF2028E题解参与者 1已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miqmwg7v
此快照首次捕获于
2025/12/04 07:24
3 个月前
此快照最后确认于
2025/12/04 07:24
3 个月前
查看原文
挺有意思的一道题。
d(u)d(u) 表示在 uu 的儿子当中最靠近叶节点的儿子。显然这个东西可以直接搜索出来。
以下设 v=d(u)v = d(u)
fuf_u 表示 Alice 从 uu 爬到根的概率。
分两种情况:
  • 这次由她走。因为她想跑掉,所以她会选择更靠近根节点的点走,那她肯定是选父节点,则概率为 ffaf_{fa}
  • 这次由女王走。因为女王想杀死她,所以肯定会将她拉到一个最靠近叶节点的位置,同时只能移动一步,所以这个点一定是 vv,则概率为 fvf_v
所以可以得出: fu=12(fv+ffa)f_u = \frac{1}{2} (f_v + f_{fa})
乘以 12\frac{1}{2} 是因为两种情况要平摊 11 的概率。
显然,这个东西有后效性无法转移,所以要让它变一下形式。
推式子
由此引发猜想:fuf_u 可以表示成 kuffak_uf_{fa} 的形式,那我们尝试解一下。
有: fu=12(fv+ffa)f_u = \frac{1}{2} (f_v+f_{fa}) 2fu=fv+ffa2f_u = f_v+f_{fa} 2fu=kvfu+ffa2f_u = k_vf_u+f_{fa} (2kv)fu=ffa(2-k_v)f_u=f_{fa} fu=12kvffaf_u = \frac{1}{2 - k_v}f_{fa}
\therefore ku=12kvk_u = \frac{1}{2 - k_v}
所以我们就只需要将 kuk_u 递归求出,再递归求出 fuf_u 就好了。
关于取模的话,用逆元求出就好了。

代码

CPP
#include<iostream>
#include<cstring>
using namespace std;
int n;
const int N=5e5+10,mod=998244353;
int h[N],e[N],ne[N],idx,g[N],dep[N];
void add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
long long f[N],k[N];
int la;
void init(){
	for(int i=1;i<=la;i++){
		h[i]=-1,f[i]=k[i]=g[i]=dep[i]=0;
	}
	idx=0;
}
long long pow(long long a,int b){
	long long res=1;
	while(b){
		if(b&1){
			res=res*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return res;
}
long long ny(long long a,long long b){
	return a*pow(b,mod-2)%mod;
}
void dfs1(int u,int fa){
	dep[u]=2e9;
	int cnt=0;
	for(int i=h[u];~i;i=ne[i]){
		int j=e[i];
		if(j==fa){
			continue;
		}
		cnt++;
		dfs1(j,u);
		dep[u]=min(dep[u],dep[j]+1);
		if(dep[j]+1==dep[u]){
			g[u]=j;
		}
	}
	if(!cnt){
		dep[u]=0;
	}
}
void dfs2(int u,int fa){
	int cnt=0;
	for(int i=h[u];~i;i=ne[i]){
		int j=e[i];
		if(j==fa){
			continue;
		}
		cnt++;
		dfs2(j,u);
	}
	if(cnt){
		int v=g[u];
		k[u]=ny(1ll,(2-k[v]+mod)%mod);
	}
}
void dfs3(int u,int fa){
	for(int i=h[u];~i;i=ne[i]){
		int j=e[i];
		if(j==fa){
			continue;
		}
		f[j]=k[j]*f[u]%mod;
		dfs3(j,u);
	}
}
int main(){
	int t;
	cin>>t;
	la=N-1;
	while(t--){
		init();
		scanf("%d",&n);
		for(int i=1;i<n;i++){
			int a,b;
			scanf("%d%d",&a,&b);
			add(a,b),add(b,a);
		}
		dfs1(1,-1);
		dfs2(1,-1);
		f[1]=1ll;
		dfs3(1,-1);
		for(int i=1;i<=n;i++){
			printf("%lld ",f[i]);
		}
		printf("\n");
		la=n;
	}
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...