「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」新年的叶子的更多相关文章

  1. 「TJOI2015」概率论 解题报告

    「TJOI2015」概率论 令\(f_i\)代表\(i\)个点树形态数量,\(g_i\)代表\(i\)个点叶子个数 然后列一个dp \[ f_i=\sum_{j=0}^{i-1} f_j f_{i-j ...

  2. loj#2009.「SCOI2015」小凸玩密室

    题目链接 loj#2009. 「SCOI2015」小凸玩密室 题解 树高不会很高<=20 点亮灯泡x,点亮x的一个子树,再点亮x另外的子树, 然后回到x的父节点,点亮父节点之后再点亮父节点的其他 ...

  3. 【LibreOJ】#6395. 「THUPC2018」城市地铁规划 / City 背包DP+Prufer序

    [题目]#6395. 「THUPC2018」城市地铁规划 / City [题意]给定n个点要求构造一棵树,每个点的价值是一个关于点度的k次多项式,系数均为给定的\(a_0,...a_k\),求最大价值 ...

  4. LOJ #2585. 「APIO2018」新家

    #2585. 「APIO2018」新家 https://loj.ac/problem/2585 分析: 线段树+二分. 首先看怎样数颜色,正常的时候,离线扫一遍右端点,每次只记录最右边的点,然后查询左 ...

  5. Loj #2568. 「APIO2016」烟花表演

    Loj #2568. 「APIO2016」烟花表演 题目描述 烟花表演是最引人注目的节日活动之一.在表演中,所有的烟花必须同时爆炸.为了确保安全,烟花被安置在远离开关的位置上,通过一些导火索与开关相连 ...

  6. Loj #3044. 「ZJOI2019」Minimax 搜索

    Loj #3044. 「ZJOI2019」Minimax 搜索 题目描述 九条可怜是一个喜欢玩游戏的女孩子.为了增强自己的游戏水平,她想要用理论的武器武装自己.这道题和著名的 Minimax 搜索有关 ...

  7. Loj #2570. 「ZJOI2017」线段树

    Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...

  8. 「APIO2016」烟花表演

    「APIO2016」烟花表演 解题思路 又是一道 solpe trick 题,观察出图像变化后不找一些性质还是挺难做的. 首先令 \(dp[u][i]\) 为节点 \(u\) 极其子树所有叶子到 \( ...

  9. 「NOI2012」迷失游乐园

    「NOI2012」迷失游乐园 题目描述 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩. 进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该 ...

随机推荐

  1. [ JS 进阶 ] 闭包,作用域链,垃圾回收,内存泄露

    原网址:https://segmentfault.com/a/1190000002778015 1. 什么是闭包? 来看一些关于闭包的定义: 闭包是指有权访问另一个函数作用域中变量的函数 --< ...

  2. Problem 2278 YYS (FZU + java大数)

    题目链接:http://acm.fzu.edu.cn/problem.php?pid=2278 题目: 题意: 有n种卡牌,每种卡牌被抽到的概率为1/n,求收齐所有卡牌的天数的期望. 思路: 易推得公 ...

  3. NYOJ 1012 RMQ with Shifts (线段树)

    题目链接 In the traditional RMQ (Range Minimum Query) problem, we have a static array A. Then for each q ...

  4. Hadoop笔记之搭建环境

    Hadoop的环境搭建分为单机模式.伪分布式模式.完全分布式模式. 因为我的本本比较挫,所以就使用伪分布式模式. 安装JDK 一般Linux自带的Java运行环境都是Open JDK,我们到官网下载O ...

  5. hdu 5319 Painter(杭电多校赛第三场)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5319 Painter Time Limit: 2000/1000 MS (Java/Others)   ...

  6. 绿色的银行类cms管理系统模板——后台

    链接:http://pan.baidu.com/s/1pK7Vu9X 密码:4cc5

  7. P-R曲线及与ROC曲线区别

    一.P-R曲线 P-R曲线刻画查准率和查全率之间的关系,查准率指的是在所有预测为正例的数据中,真正例所占的比例,查全率是指预测为真正例的数据占所有正例数据的比例. 即:查准率P=TP/(TP + FP ...

  8. JVM内存分配及GC简述

    在阐述JVM的内存区域之前,先来看下计算机的存储单位.从小到大依次为Bit,Byte,KB,MB,GB,TB.相邻的单位相差2的10次方. 计算机运行中的存储元件主要分为寄存器(位于CPU)和内存,寄 ...

  9. laravel入门教程

    参考地址:https://github.com/johnlui/Learn-Laravel-5/issues/16

  10. C# 随笔 【ToList().Foreach()和Foreach()】

    1. 最近在做一个Socket通讯的例子,但是如果使用UTF-8编码传输中文的话取和的会不一样.早上做了测试 . string str = "a我..";看代码中间是一个英文,一个 ...