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

CF123E maze 题解

时间:2023-03-21 15:47:30浏览次数:43  
标签:CF123E 终点 int 题解 贡献 si maze now 起点

思考暴力:枚举起点和终点,再枚举每一种遍历序列得到答案。复杂度起飞。

根据期望的可加性,我们无需硬着头皮统计每一条序列的贡献,而是把序列的贡献拆成遍历序列包含的边的贡献。换句话说,假如 \(Edge\) 为遍历时经过的边集,\(e\) 为边,则:

\[E[Edge] = \sum_{e\in Edge} E[e] \]

以上为第一部分,我们将路径贡献通过期望的性质拆成了更好计算的边的贡献。


考虑边的贡献:在固定起点与终点的情况下,我们把边分为三种:在起点到终点必经之路(最短路径)上的,不在必经之路上的,与不可能走到的(这些边在以起点为根时终点的子树内)。

第一种边贡献为 \(1\)。因为我们必须经过这条边,且因为遍历方式为深度优先搜索,一定会在经过这条边后搜到终点结束,不可能再走第二次。

现在我们思考第二种边的贡献。我们设起点为根节点,并设这条边深度较浅的点为 \(u\)。我们让 \(u\) 往上跳,直到遇到一个必经之路上的点 \(fa\)。我们令这条必经之路上边的下一个点为 \(w\)。

显然,\(u\) 与 \(w\) 分属 \(fa\) 的不同子树。假如我们先进入了 \(u\) 的子树,由于终点不在其中,所以会全遍历一遍后回溯,此时这条边贡献为 \(2\),因为进去和出来按照题目要求要算两次。

假如我们先进入了 \(w\),就不会再出来,而是遍历到终点后结束答案。此时这条边不会被计算到,贡献为 \(0\)。

而 \(u\) 和 \(w\) 先进哪棵子树完全取决于它们在遍历序列中的先后。由于序列随机,所以概率各为 \(50\%\)。

这时我们可以发现,第二种边对期望的贡献同样为 \(1\)。也就是说,固定起点终点,假如第三种边有 \(m\) 条,那么我们要求的期望就是 \(n - 1 - m\)。

以上为第二部分,我们将边的贡献分类讨论,最终简化了要求的问题。


那么我们来思考怎么快速求出最终答案。对于一个点 \(u\),我们思考他作为终点的情况(此时我们设 \(1\) 为根)。对于他的每棵子树,我们求出其内所有节点作为起点的概率和 \(f_v\),那么以这些点作为起点能够走到的边数就是子树大小(因为包括了连向 \(u\) 的边)。所以贡献为 \(u\times f_v\times si_v\)。

当然还有不是他子树作为起点的路径,这些路径的概率和为 \(1-f_u\),边集大小为 \(1-si_u\),按照上面的方式也能简单计算。

当然,钦定 \(u\) 作为起点运算也是可以的。以上为第三部分。


顺便一提这道题是我见过的少有的卡关闭同步流 cin 的题。请注意使用更快的输入方式。

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;

int n;
vector<int> e[N];
double x[N], y[N], sumX, sumY;
int si[N];
double f[N];
double ans;
double now;

void dfs(int u, int fa) {
	si[u] = 1;
	for (auto v : e[u]) {
		if (v == fa) continue;
		dfs(v, u);
		f[u] += f[v];
		si[u] += si[v];
	}
	f[u] += x[u];
}
signed main() {
  // freopen("text.in", "r", stdin);
	scanf("%d", &n);
	int u, v;
	for (int i = 1; i < n; ++i) {
		scanf("%d%d", &u, &v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	for (int i = 1; i <= n; ++i) {
		scanf("%d%d", &x[i], &y[i]);
		sumX += x[i], sumY += y[i];
	}

	for (int i = 1; i <= n; ++i) x[i] /= sumX;
	for (int i = 1; i <= n; ++i) y[i] /= sumY;

	dfs(1, -1);

	double ans=0;
	for (int now = 1; now <= n; ++now) {
		for (auto v : e[now]) {
			if (si[v] > si[now]) continue;
			ans += f[v] * y[now] * si[v];
		}
		ans += (1 - f[now]) * y[now] * (n - si[now]);
	}

	printf("%.10lf\n", ans);
	
	return 0;
}

标签:CF123E,终点,int,题解,贡献,si,maze,now,起点
From: https://www.cnblogs.com/closureshop/p/solution-CF123E.html

相关文章

  • 蓝桥楼赛第9期-修复未正确实现的实验类 题解
    题目描述程序存放的位置/home/shiyanlou/lab.py;实验类名应该为Lab;实验对象中不能插入重复标签;Python中对象引用问题,尤其如复合对象list,dict,tuple的......
  • 【AT_abc294_g 题解】
    题意给定一颗\(n\)个节点的带权无向树。给出\(q\)个操作:1iw:把第\(i\)条边的边权变成\(w\)。2uv:求\(u\tov\)简单路径的边权和。解法根据树上差分。......
  • ABC288Ex 题解
    题意传送门给定\(n,m,x\),询问有多少个长度为\(n\)的非负整数序列满足以下条件:\(0\lea_1\lea_2\le\dots\lea_n\lem\)\(a_1\oplusa_2\oplus\dots\oplusa_n=x\)......
  • 问题解决01:默认不执行.ps1文件 - 无法双击.ps1文件
    默认不允许执行.ps1文件扩展名为.ps1的文件是用PowerShell写好的脚本文件。在Windows系统中,默认情况下是不允许执行.ps1文件。想双击一下执行.ps1文件?双击ps1文件很有......
  • 【题解】CF1034E
    题目描述给定\(n\)和长度为\(2^n\)的数列\(a_{0},a_{1}...a_{2^n-1}\)和\(b_{0},b_1...b_{2^n-1}\),保证每个元素的值属于\([0,3]\)生成序列\(c\),对于\(......
  • 【题解】CF889E
    题目描述\[f(x,n)=x\moda_n\]\[f(x,i)=(x\moda_i)+f(x\moda_i,i+1)\]给出a序列,当x取遍所有非负整数时\(f(x,1)\)的最大值。题解首先注意到\(a_i\)只......
  • 【题解】CF1368E
    题目描述有一个由\(n\)个点\(m\)条边组成的有向无环图,每个点出度至多为2。您需要标记一些点(不超过\(\frac{4}{7}n\)个)。标记一个点\(u\)将会删除所有与\(u\)连......
  • 【题解】CF1225F
    题目描述给出一棵n个节点的有根树T,点编号为0∼n−1。记f(u)为u的父节点。初始时你有一条n个点的链L(标号任意),每次操作你可以令f(u)←f(f(u))。需要将链改造......
  • 【题解】CF1439A2
    题目描述给定一个\(n\timesm\)的\(01\)矩阵,每次操作可以将某个\(2\times2\)的矩阵内的\(3\)个数取反,请在\(n\timesm\)步内将矩阵变为全\(0\)。题解这种题......
  • C# 上传接口返回错误: (413) Request Entity Too Large问题解决
    问题报错:Failedtoloadresource:theserverrespondedwithastatusof413(RequestEntityTooLarge)找了很多方法,说什么反向代理配置啥的其实很多项目并没有开反......