【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个点的树,每条边有边权,请你求出最长的一条路径 ...
随机推荐
- WPF EventTrigger,BeginStoryboard
<Window x:Class="WpfApplication2.LoginWind" xmlns="http://schemas.microsoft.com/wi ...
- 20155232《网络对抗》Exp5 MSF基础应用
20155232<网络对抗>Exp5 MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode. exploit:就是利用可能存在的漏洞对目标进行攻击 ...
- 20155311高梓云《网络对抗》逆向及Bof基础
20155311高梓云<网络对抗>逆向及Bof基础 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任 ...
- 基于RapidJSON的操作库
需要安装配置RapidJSON库 /******************************************************************* * summery: 提供便 ...
- metasploit-smb扫描获取系统信息
1.msfconsle 2.use auxiliary/scanner/smb/smb_version 3. msf auxiliary(smb_version) > set RHOSTS 17 ...
- JavaScript快速入门-ECMAScript本地对象(String)
一.String对象 String对象和python中的字符串一样,也有很多方法,这些方法大概分为以下种类: 1.索引和查找 1.charAt() 返回指定位置的字符. 2.charCodeAt( ...
- Reflux系列01:异步操作经验小结
写在前面 在实际项目中,应用往往充斥着大量的异步操作,如ajax请求,定时器等.一旦应用涉及异步操作,代码便会变得复杂起来.在flux体系中,让人困惑的往往有几点: 异步操作应该在actions还是s ...
- centos7 lldb 调试netcore应用的内存泄漏和死循环示例(dump文件调试)
写个demo来玩一玩linux平台下使用lldb加载sos来调试netcore应用. 当然,在真实的产线环境中需要分析的数据和难度远远高于demo所示,所以demo的作用也仅仅只能起到介绍工具的作用. ...
- Asp.Net_的传值跟存储值操作
页面传值是学习asp.net初期都会面临的一个问题,总的来说有页面传值.存储对象传值.ajax.类.model.表单等.但是一般来说,常用的较简单有QueryString,Session,Cookie ...
- Go语言实现数据结构(一)单链表
1.基本释义 2.结构体设计 3.基本方法设计 4.Main函数测试 1. 基本释义 线性表包含两种存储方法:顺序存储结构和链式存储结构,其中顺序表的缺点是不便插入与删除数据:接下来我们重点实现基于G ...