【UOJ #351】新年的叶子(树的直径,期望)
这的确是一道好题,我们不妨依循思路一步步推导,看问题是如何被解决的。
做一些约定,设$m$为树的叶子节点个数,设$len$为该树的直径(经过的点数)。
毫无疑问,直径可能有多条,我们需要把所有直径都破坏掉才能终止,但这些直径并不是毫无联系的。
引理:若$len$为奇数,则所有直径有同一个中点;若$len$为偶数,则所有直径有同一条最中间的边。
- 至于证明,用反证法即可,大致就是如果存在两条直径的中点不是同一个,那就会产生更长的一条直径。
题目要求的终止状态就是不存在两个可以构成直径的点,可以构成直径的点指的是原先处在某一条直径的两端的点,我们可以先按$len$的奇偶讨论:
- 若$len$为奇数,即存在一个中点$x$,我们不妨将$x$设成根,不难发现,如果两个点$a,b$的$lca$是$x$,那$a,b$就能构成直径,否则就不能。这启发我们把所有可以构成直径的点,按照他们在$x$的哪个亲儿子下分组,那样同一个组内的点互相不能构成直径,不在一个组内的两点能构成直径。
- 若$len$为偶数,即所有直径都会经过中间两个点,我们模仿之前的思路,从这两个点之间分开,把这些可以构成直径的点分成的两个组,道理同上。
这样我们得到了若干个点的集合,假设我们得到了$t$个集合,其集合大小用$k$表示,所有集合大小之和用$sum$表示,并且我们只关心集合的大小,集合中具体有那些点并不重要。然后我们发现,如果存在两个集合都没有被完全染黑,原先的直径还是存在的,也就是说我们第一次使得只剩下一个集合没有被完全染黑的时间就是我们所希望的。
我们按照这个精简后的题目做,这里有两种做法,分别从两个不同角度求解。
法一:
在此之前,我们必须先明白一件事,期望实际上是若干个随机事件的概率乘上该事件的价值的和。
我们知道经过无限次染色后所有叶子终究都会被染黑,而每一种染黑的方案中这些叶子被染黑是有顺序的,由于每次染色都是随机的,所以产生每一种顺序的概率是均等的,但是不同的顺序会导致它们终止的时间不同。所以这个做法总体上是把所有事件按照点染黑的顺序分组分别算,最后把贡献加起来。
有诸多顺序它们的期望步数是相等的,我们会把它们合起来算。我们枚举一个集合,将它作为最后那个没有被完全染黑的集合,并枚举这个集合在终止时有多少个点已经被染黑了,显然所有满足以此为终止状态的顺序的期望步数都是一样的。这里要注意的是,染黑的最后一个点一定是其它集合中的点,这是需要特殊考虑的。
于是我们可以写出贡献和的表达式:
$$ans = \frac{1}{sum!} \sum_{i = 1}^{t} \sum_{j = 0}^{k_i - 1} \tbinom{k_i}{j} (m - k_i) (m - k_i + j - 1)! (k - j)! \sum_{z = k_i - j + 1}^{sum} \frac{m}{z}$$
这里可能有些需要解释的地方,就是为什么这么算是对的,这可能一开始看会觉得难以理解。你会发现对于每一个顺序而言,我们让$\sum_{z} \frac{m}{z}$成为它的贡献的行为令人费解,因为这个式子在做的东西是无序的,并没有按照我们所想的顺序染色。但是每个顺序的概率是均等的,我们仅仅只需要这个期望式子中的一部分,只要把$sum!$除掉就可以了。
法二:
既然我们要算的是所有合法事件的概率乘贡献之和(这里所说的合法事件指第一次使得只剩下一个集合没有被完全染黑,因为只有这些是被算进答案里的),用容斥也是可以得到的。
如果我们枚举一个集合$i$,想要让$i$成为最后那个没有被完全染黑的集合,我们算出只关心其余集合的点把它们染黑的期望时间。在这个期望中,每一种方案的最后一个染色的点一定不在$i$中。这里有两种情况,一种是在染色结束时$i$中仍存在没染黑的点,这属于合法情况;另一种是$i$中的点已经全部被染黑了,也就是所有点都没染黑了,这是需要去掉的。我们考虑每一种全部染黑的方案会在除了最后染色的集合外的其他$t-1$个集合中都被算到,所以最终的答案就是枚举每个集合算其余点被染黑的期望时间减去$t-1$倍的把所有点都染黑的期望时间。
我们发现这么容斥后,剩下的事件的概率和恰好是$1$,单纯从概率分支树上来讲肯定是对的。具体来讲就是一种全部染黑的方案事实上是一种合法方案的一个分支,本来就不应该算进去,而合法事件显然是不重复不遗漏的。
这是法二的实现:
#include <cstdio>
#include <algorithm> using namespace std; typedef long long LL; const int N = ;
const int MOD = ; int n, m, bt, len, su, ans, tmp;
int bl[N], inv[N], sui[N], dep[N], fa[N], deg[N]; int yu, la[N], to[N << ], pr[N << ];
inline void Ade(int a, int b) {
to[++yu] = b, pr[yu] = la[a], la[a] = yu;
} void Dfs(int x, int fat, int &c) {
dep[x] = dep[fa[x] = fat] + ;
if (dep[x] == len / ) ++c;
for (int i = la[x]; i; i = pr[i])
if (to[i] != fat) Dfs(to[i], x, c);
} inline int Add(int a, int b) {
return (a += b) >= MOD? a - MOD : a;
} int main() {
scanf("%d", &n);
for (int i = , x, y; i < n; ++i) {
scanf("%d%d", &x, &y);
Ade(x, y), Ade(y, x);
++deg[x], ++deg[y];
}
Dfs(, , tmp);
int rt = , tl = ;
for (int i = ; i <= n; ++i) {
if (dep[i] > dep[rt]) rt = i;
if (deg[i] == ) ++m;
}
Dfs(rt, , tmp);
for (int i = ; i <= n; ++i)
if (dep[i] > dep[tl]) tl = i;
len = dep[tl];
inv[] = , sui[] = m;
for (int i = ; i <= n; ++i) {
inv[i] = MOD - (LL)MOD / i * inv[MOD % i] % MOD;
sui[i] = Add(sui[i - ], (LL)m * inv[i] % MOD);
}
if (len & ) {
int md = -;
for (int i = tl; i; i = fa[i])
if (dep[i] == (len + ) / ) md = i;
dep[md] = ;
for (int i = la[md]; i; i = pr[i]) {
Dfs(to[i], md, tmp = );
if (tmp) bl[++bt] = tmp, su += bl[bt];
}
} else {
int m1 = -, m2 = -;
for (int i = tl; i; i = fa[i]) {
if (dep[i] == len / ) m1 = i;
if (dep[i] == len / + ) m2 = i;
}
dep[m2] = , Dfs(m1, m2, bl[++bt]);
dep[m1] = , Dfs(m2, m1, bl[++bt]);
su = bl[] + bl[];
}
for (int i = ; i <= bt; ++i)
ans = Add(ans, sui[su - bl[i]]);
ans = Add(ans, MOD - (bt - 1LL) * sui[su] % MOD);
printf("%d\n", ans);
return ;
}
【UOJ #351】新年的叶子(树的直径,期望)的更多相关文章
- [UOJ#351]新年的叶子
[UOJ#351]新年的叶子 试题描述 躲过了AlphaGo 之后,你躲在 SingleDog 的长毛里,和它们一起来到了AlphaGo 的家.此时你们才突然发现,AlphaGo 的家居然是一个隐藏在 ...
- UOJ#351. 新年的叶子 概率期望
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ351.html 题目传送门 - UOJ351 题意 有一个 n 个节点的树,每次涂黑一个叶子节点(度为 1 ...
- uoj#351. 新年的叶子(概率期望)
传送门 数学还是太差了,想了半天都没想出来 首先有一个定理,如果直径(这里考虑经过的点数)为奇数,所有直径有同一个中点,如果直径为偶数,所有直径有同一条最中间的边.这个可以用反证法,假设不成立的话直径 ...
- 「UOJ351」新年的叶子
「UOJ351」新年的叶子 题目描述 有一棵大小为 \(n\) 的树,每次随机将一个叶子染黑,可以重复染,问期望染多少次后树的直径会缩小. \(1 \leq n \leq 5 \times 10^5\ ...
- HDU 4123(树的直径+单调队列)
Bob’s Race Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- HDU 4612 Warm up(双连通分量缩点+求树的直径)
思路:强连通分量缩点,建立一颗新的树,然后求树的最长直径,然后加上一条边能够去掉的桥数,就是直径的长度. 树的直径长度的求法:两次bfs可以求,第一次随便找一个点u,然后进行bfs搜到的最后一个点v, ...
- CF835F Roads in the Kingdom/UOJ126 NOI2013 快餐店 树的直径
传送门--CF 传送门--UOJ 题目要求基环树删掉环上的一条边得到的树的直径的最小值. 如果直接考虑删哪条边最优似乎不太可做,于是考虑另一种想法:枚举删掉的边并快速地求出当前的直径. 对于环上的点, ...
- 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分
树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...
- 牛客网 桂林电子科技大学第三届ACM程序设计竞赛 G.路径-带条件的树的直径变形-边权最大,边数偶数的树上的最长路径-树形dp
链接:https://ac.nowcoder.com/acm/contest/558/G 来源:牛客网 路径 小猫在研究树. 小猫在研究路径. 给定一棵N个点的树,每条边有边权,请你求出最长的一条路径 ...
随机推荐
- 20155213免考项目——简易的HIDAttack
20155213免考项目--简易的HIDAttack 听5214说他做不出来自己的免考项目,于是就转向bof进阶,并且成功做出了64位的ROP攻击...... 既然如此,那我就再做一个吧,但都已经期末 ...
- 20155321 《网络攻防》 Exp9 Web安全基础
20155321 <网络攻防> Exp9 Web安全基础 基础问题 SQL注入攻击原理,如何防御 原理:在事先定义好的SQL语句的结尾上添加额外的SQL语句(感觉一般是或上一个永真式),以 ...
- R语言学习 第三篇:数据框
数据框(data.frame)是最常用的数据结构,用于存储二维表(即关系表)的数据,每一列存储的数据类型必须相同,不同数据列的数据类型可以相同,也可以不同,但是每列的行数(长度)必须相同.数据框的每列 ...
- laraver框架学习------工厂模型填充测试数据
在laravel中填充数据有几种方式.一种是Seeder,另一种是工厂模式进行的填充. 工厂模式可以实现大批量的填充数据,数据的量可以自定义.这也为后续的软件测试提供方便. 在laravel框架有da ...
- kubernetes 集群新增node 节点并将应用分配到新增节点
第一章 1.重新安装一台kubernetes node节点,新增节点:192.168.1.192 网址:https://www.cnblogs.com/zoulixiang/p/9504324.htm ...
- 实验吧ctf题库web题wp
经历了学校的校赛,一度自闭,被大佬们刺激的要奋发图强. 1.后台登录 链接: http://ctf5.shiyanbar.com/web/houtai/ffifdyop.php 打开题目首先查看源码, ...
- PAT甲题题解-1127. ZigZagging on a Tree (30)-中序、后序建树
根据中序遍历和前序遍历确定一棵二叉树,然后按“层次遍历”序列输出.输出规则:除根节点外,接下来每层的节点输出顺序是:先从左到右,再从右到左,交替输出 #include <iostream> ...
- Github与SmartGit使用说明与建议
当使用github做协同的时候,我们常常需要在客户端安装相应的软件,SmartGit就是一款非常出色的软件,不过是要付费的,我们可以使用non-commercial版本. Download: http ...
- 20135202闫佳歆--week3 构造一个简单的Linux系统MenuOs--学习笔记
此为个人学习笔记存档 week 3 构造一个简单的Linux系统MenuOs 复习: 计算机有三个法宝:存储程序计算机,函数调用堆栈,中断 操作系统有两把剑: 1.中断上下文的切换,保存现场和恢复现场 ...
- 重温httpsession①
Session—HTTPSession 服务器创建的,Javaweb提供的 与HTTP协议无关是服务器端对象,保存在服务器端.用来会话跟踪. Cookie与服务器创建,与HTTP协议相关,保存在客户端 ...