「UOJ351」新年的叶子
「UOJ351」新年的叶子
题目描述
有一棵大小为 \(n\) 的树,每次随机将一个叶子染黑,可以重复染,问期望染多少次后树的直径会缩小。\(1 \leq n \leq 5 \times 10^5\)
解题思路 :
首先要利用一个经典的结论,树的所有直径的中心为同一个点/边。不妨给每条边加一个虚拟点,这样整颗树的直径就只会交于同一个点了。
接下来考虑树的直径是由中心的两个儿子的两个深度为 \(maxdep\) 的叶子构成的,所以问题等价于将叶子根据中心的儿子分成若干个集合,对于所有染色方案求染到只剩一个集合没有被完全染黑的期望步数之和,这个东西再除以一个方案数就是答案。
这个东西好难求啊,推了半天式子还是不太会,最后只能看题解辅助推导 \(\text{qwq}\) 。首先把随机染黑一个叶子转化为随机染黑一个没有染黑的叶子,那么此时的期望步数就是总叶子数除以没有被染黑的叶子数。然后枚举一下最后一个被染黑的集合是哪个集合,在第一次到达只有它没被完全染黑这个状态之前其被染黑的叶子总数是多少,不妨分别设他们为 \(i, k\) 。那么首先先选出 \(k\) 个叶子染黑,其在操作序列中有 \(n - sz_i+k-1\) 个位置可以放,\(-1\) 是因为不能放最后一个位置,如果放了最后一个位置其就不是第一次到达的状态就算重了,然后把其它的操作的排列数乘上就是方案数。而步数就是 \(\sum_{i=sz_i-k+1}^{n} \frac{m}{i}\) ,其中 \(n\) 是集合总大小,\(m\) 是总的叶子数量。 由于我的写法常数太大,在 UOJ 上的统计榜成功吃鸡。
/*program by mangoyang*/
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define pii pair<int, int>
#define fi first
#define se second
const int N = 1000005, mod = 998244353;
vector<int> g[N];
int dep[N], f[N], js[N], inv[N], buf[N], n, m, all, mxdep, rt;
ll h[N], ans;
namespace prework{
queue<pii> q; int vis[N], pre[N];
inline pii bfs(int s){
memset(vis, 0, sizeof(vis));
q.push(make_pair(s, 0)), vis[s] = 1; pii res;
while(!q.empty()){
pii now = q.front(); q.pop();
int x = now.fi, dis = now.se; res = now;
for(int i = 0; i < g[x].size(); i++){
int v = g[x][i];
if(vis[v]) continue;
vis[v] = 1, pre[v] = x;
q.push(make_pair(v, dis + 1));
}
}
return res;
}
inline void dfs(int u, int fa){
dep[u] = dep[fa] + 1, f[u] = dep[u], buf[u] = 1;
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i];
if(v == fa) continue;
dfs(v, u);
if(f[v] > f[u]) buf[u] = buf[v], f[u] = f[v];
else if(f[v] == f[u]) buf[u] += buf[v];
}
if(g[u].size() == 1 && fa) m++;
}
inline void realmain(){
pii s1 = bfs(1), s2 = bfs(s1.fi);
int dis = s2.se / 2; rt = s2.fi;
for(int i = 1; i <= dis; i++) rt = pre[rt];
dfs(rt, 0);
}
}
inline void up(ll &x, int y){ (x += y) %= mod; }
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline int C(int x, int y){
return 1ll * js[x] * inv[y] % mod * inv[x-y] % mod;
}
inline int calc(int x, int y){
ll res = 1ll * C(y, x) * C(all-(y-x)-1, x) % mod;
(res *= (1ll * js[y-x] * js[all-y] % mod)) %= mod;
(res *= (1ll * js[x] * (h[all] - h[y-x]) % mod)) %= mod;
return res;
}
int main(){
js[0] = inv[0] = 1;
for(int i = 1; i < N; i++)
js[i] = 1ll * js[i-1] * i % mod, inv[i] = Pow(js[i], mod - 2);
read(n); int size = n;
for(int i = 1, x, y; i < n; i++){
read(x), read(y), ++size;
g[x].push_back(size), g[size].push_back(x);
g[y].push_back(size), g[size].push_back(y);
}
prework::realmain();
for(int i = 1; i <= m; i++)
up(h[i], 1ll * (h[i-1] + 1ll * m * Pow(i, mod - 2)) % mod);
for(int i = 0; i < g[rt].size(); i++) mxdep = max(mxdep, f[g[rt][i]]);
for(int i = 0; i < g[rt].size(); i++){
if(f[g[rt][i]] == mxdep) all += buf[g[rt][i]];
else buf[g[rt][i]] = 0;
}
for(int i = 0; i < g[rt].size(); i++)
for(int j = 0; j < buf[g[rt][i]]; j++) up(ans, calc(j, buf[g[rt][i]]));
cout << (1ll * ans * inv[all] % mod + mod) % mod;
return 0;
}
「UOJ351」新年的叶子的更多相关文章
- 「TJOI2015」概率论 解题报告
「TJOI2015」概率论 令\(f_i\)代表\(i\)个点树形态数量,\(g_i\)代表\(i\)个点叶子个数 然后列一个dp \[ f_i=\sum_{j=0}^{i-1} f_j f_{i-j ...
- loj#2009.「SCOI2015」小凸玩密室
题目链接 loj#2009. 「SCOI2015」小凸玩密室 题解 树高不会很高<=20 点亮灯泡x,点亮x的一个子树,再点亮x另外的子树, 然后回到x的父节点,点亮父节点之后再点亮父节点的其他 ...
- 【LibreOJ】#6395. 「THUPC2018」城市地铁规划 / City 背包DP+Prufer序
[题目]#6395. 「THUPC2018」城市地铁规划 / City [题意]给定n个点要求构造一棵树,每个点的价值是一个关于点度的k次多项式,系数均为给定的\(a_0,...a_k\),求最大价值 ...
- LOJ #2585. 「APIO2018」新家
#2585. 「APIO2018」新家 https://loj.ac/problem/2585 分析: 线段树+二分. 首先看怎样数颜色,正常的时候,离线扫一遍右端点,每次只记录最右边的点,然后查询左 ...
- Loj #2568. 「APIO2016」烟花表演
Loj #2568. 「APIO2016」烟花表演 题目描述 烟花表演是最引人注目的节日活动之一.在表演中,所有的烟花必须同时爆炸.为了确保安全,烟花被安置在远离开关的位置上,通过一些导火索与开关相连 ...
- Loj #3044. 「ZJOI2019」Minimax 搜索
Loj #3044. 「ZJOI2019」Minimax 搜索 题目描述 九条可怜是一个喜欢玩游戏的女孩子.为了增强自己的游戏水平,她想要用理论的武器武装自己.这道题和著名的 Minimax 搜索有关 ...
- Loj #2570. 「ZJOI2017」线段树
Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...
- 「APIO2016」烟花表演
「APIO2016」烟花表演 解题思路 又是一道 solpe trick 题,观察出图像变化后不找一些性质还是挺难做的. 首先令 \(dp[u][i]\) 为节点 \(u\) 极其子树所有叶子到 \( ...
- 「NOI2012」迷失游乐园
「NOI2012」迷失游乐园 题目描述 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩. 进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该 ...
随机推荐
- 游戏AI:行为树
Behavior Tree 行为树通过子Task的返回值决定整棵树的走向 Task 行为树上的每个节点都称为一个Task, 每个Task存在三种状态, success, failure, runnin ...
- CALayer---iOS-Apple苹果官方文档翻译之CALayer
CHENYILONG Blog CALayer---iOS-Apple苹果官方文档翻译之CALayer CALayer /*技术博客http://www.cnblogs.com/ChenYilong/ ...
- Linux下命令lrzsz
lrzsz是什么 在使用Linux的过程中,难免少不了需要上传下载文件,比如往服务器上传一些war包之类的,之前都是使用winSCP,lrzsz是一个更方便的命令,可以直接在Linux中输入命令,弹出 ...
- 人脸识别如何做到one-shot learning?(转)
来源:http://blog.csdn.net/ice_actor/article/details/78603042 1.什么是人脸识别 这部分演示了百度总部大楼的人脸识别系统,员工刷脸进出办公区 ...
- 一. Jmeter--使用代理录制脚本
Jmeter脚本是以.JMX格式为主 1. Jmeter也是支持录制的,支持第三方录制方式和代理录制方式. (1).第三方录制主要是通过badboy来录制,录制后另存为jmx格式即可. (2).Jme ...
- PHP中的 get_magic_quotes_runtime
get_magic_quotes_runtime() 获得外部文件及数据库资料时是否进行转义 set_magic_quotes_runtime(1); 临时设置获得外部文件及数据库资料时是否进行转义 ...
- 在C#中用MediaInfo获取视频或音频的属性
MediaInfo是一个开源的获取视频或音频的信息的非常便利的工具,它本身就带有一个GUI界面,可以非常方便我们查看视频信息.但是,当我们写一些转码程序时,往往需要在程序中获取视频信息的时候. 以前我 ...
- 安装Https证书
安装证书 IIS 6 支持PFX格式证书,下载包中包含PFX格式证书和密码文件.以沃通证书为例: 文件说明: 1. 证书文件214083006430955.pem,包含两段内容,请不要删除任何一段内容 ...
- 自己实现的SVM源码
首先是DATA类 import java.awt.print.Printable; import java.io.File; import java.io.FileNotFoundException; ...
- HDU 3342 Legal or Not(拓扑排序判断成环)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3342 题目大意:n个点,m条有向边,让你判断是否有环. 解题思路:裸题,用dfs版的拓扑排序直接套用即 ...