首页 > 其他分享 >CF123E Maze 题解

CF123E Maze 题解

时间:2022-08-27 18:33:13浏览次数:75  
标签:CF123E sz 子树 limits 题解 sum 终点 Maze 步数

提供一种不太一样的换根 dp 的做法。

记 \(u\) 作为起点的概率为 \(q_u\) ,作为终点的概率为 \(p_u\)。

题目给的代码可以看作一个从某个点开始,以它为根 dfs 到终点的步数,这启发我们直接考虑以每个点为根,到达所有可能终点的期望步数之和。

首先可以观察出几个性质:

假设当前的根为 \(x\),终点是 \(y\),那么从 \(x\) 开始走,考虑其中的一步。

  • 如果这一步进入了与 \(y\) 所在子树不同的一个子树,一定会把这个子树内的所有点遍历完才出来。假设进入了一个以 \(z\) 为根的子树,大小为 \(sz_z\),那么这个子树内的边数就是 \(sz_z-1\),所需步数即为 \(2(sz_z-1)+2=2sz_z\)。
  • 如果走进了了 \(y\) 所在的子树,那么就不会再出来。

对于一个点,记 \(y\) 所在的子树的根为 \(u\)。

由上面的性质可以知道,对于一个点,如果一个它的一个儿子 \(v \not=u\) 在 \(u\) 之前被访问,那么答案就会加上 \(sz_v\)。而 \(v\) 在 \(u\) 之前被访问的概率相当于给这个点的儿子随机一个排列,其中 \(v\) 在 \(u\) 之前的概率。考虑对于每种 \(v\) 在 \(u\) 之前的排列,swap(u,v) 之后就会得到一个 \(u\) 在 \(v\) 之前的排列,所以概率是 \(\dfrac 12\)。

接下来设 \(S\) 为 \((x,fa_y)\) 这条路径上的点分叉出去的点集的并,那么 \(x\) 走到 \(y\) 的期望就是 \(\sum\limits_{u \in S} \dfrac{2sz_u}{2}\),对答案的贡献就是 \(q_xp_y\sum\limits_{u \in S}sz_u\)。

接下来就考虑对于每个根 \(x\) 求出 \(p_y\sum\limits_{u \in S}sz_u\),先考虑以 \(1\) 为根。

设 \(f_u\) 表示以 \(u\) 为起点,到达 \(u\) 子树的的所有可能终点的期望步数之和,设 \(s=\sum\limits_{v \in son_u} sz_v=sz_u-1\),\(t_u=\sum\limits_{v\in Subtree_u} p_u\)。

那么转移就是 \(f_u=\sum\limits_{v \in son_u} (s-sz_v+1)t_v+f_v\)。

换根也非常容易,首先对于每个点的 \(\sum t_v\) 可以提前维护出来,这样子 \(s\) 的变化导致的答案增量也很容易算出,具体的转移可以见代码。

复杂度 \(O(n)\)。

代码:

const int N=2e5+50;
int n,x[N],y[N],head[N],cnt;
ld sum[N],sumt[N],sz[N],t[N],p[N],q[N],f[N],g[N],ans;
struct edge{int to,nxt;}e[N<<1];
inline void addedge(int u,int v){e[++cnt]=(edge){v,head[u]},head[u]=cnt;}
void dfs1(int u,int fa)
{
	sz[u]=1,t[u]=p[u];
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs1(v,u),sz[u]+=sz[v],t[u]+=t[v];
		sum[u]+=sz[v],sumt[u]+=t[v];
	}
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		f[u]+=f[v]+(sum[u]-sz[v]+1)*t[v];
	}
}
void dfs2(int u,int fa)
{
	ans+=g[u]*q[u];
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		ld fu=g[u]-sz[v]*(1-p[u])-(n-1-2*sz[v]+1)*t[v]-f[v];
		g[v]=f[v]+(n-sz[v])*sumt[v]+(n-1-(n-sz[v])+1)*(1-t[v])+fu,dfs2(v,u);
	}
}
int main(void)
{
	n=read();int u,v,sumx=0,sumy=0;
	fr(i,2,n) u=read(),v=read(),addedge(u,v),addedge(v,u);
	fr(i,1,n) x[i]=read(),y[i]=read(),sumx+=x[i],sumy+=y[i];
	fr(i,1,n) q[i]=(ld)x[i]/(ld)sumx,p[i]=(ld)y[i]/(ld)sumy;
	dfs1(1,0),g[1]=f[1],dfs2(1,0);
	printf("%.10Lf\n",ans);
	return 0;
}

标签:CF123E,sz,子树,limits,题解,sum,终点,Maze,步数
From: https://www.cnblogs.com/lgj-lgj/p/16631127.html

相关文章

  • P1002 [NOIP2002 普及组] 过河卒 题解
    题目:[NOIP2002普及组]过河卒题目描述棋盘上\(A\)点有一个过河卒,需要走到目标\(B\)点。卒行走的规则:可以向下、或者向右。同时在棋盘上\(C\)点有一个对方的马,该......
  • 洛谷 P8496 [NOI2022] 众数 题解
    最近7年最水的D1T1。用权值线段树维护每个数出现的次数,链表维护序列。操作4即合并两棵权值线段树、两个链表,操作2就是删除链表尾的元素并在权值线段树上修改。显......
  • CF1506G 题解
    前言题目传送门!更好的阅读体验?校内考试题目。写一篇题解。思路首先记录每个字符出现了多少次,然后创建单调栈。看当前字符是否入栈,如果没有入栈,就不停pop(),直到:栈......
  • P8444 题解
    前言题目传送门!更好的阅读体验?普及组月赛第二题。特殊数据好恶心啊,考试差点丢分了。思路贪心题,先给\(a\)数组排个序。首先,肯定是买小于等于\(w\)的最大价格的物......
  • CF1550C 题解
    前言题目传送门!更好的阅读体验?比赛时,这题写了一个\(O(n^3)\)算法,然后就过了。以为是数据水,实际上可以证明时间复杂度是\(O(n)\)的。思路关键是一个结论:当\(i<......
  • CF1720C 题解
    前言题目传送门!更好的阅读体验?赛时锁题后看别人代码,怎么都和我想法不一样?幸好没有被hack。思路以下把L字形的覆盖网格,直接称为L。贪心思考,我们想让每次L覆盖......
  • CF1720D1 题解
    前言题目传送门!更好的阅读体验?有点思维难度的DP优化题。小知识在做这道题之前,你需要知道:\(x-y,y-x\lex\oplusy\lex+y\)。证明非常简单,利用异或的性......
  • CF1548B 题解
    前言题目传送门!更好的阅读体验?做法:ST表加尺取。思路看到同余,立刻想到作差。我们建立差分数组\(c_i=|a_i-a_{i-1}|\),注意取了绝对值。此时,我们只需在\(c_i\)......
  • CF1715A 题解
    前言题目传送门!更好的阅读体验?赛时瞎胡了个结论,然后就过了。思路Megan从左下角到右上角,至少也得要\((n+m-1)\)步。于是考虑让Stanley少走几步。如图,容易......
  • CF1715C 题解
    前言题目传送门!更好的阅读体验?简单的数学题。思路每次只变一个数,因此考虑在短时间内计算:每个位置的数产生的贡献。容易发现以下的条件:不管\(a_i\)是什么,当它作......