题意

对于一棵 \(n\) 个点的带标号无根树,设 \(d[i]\) 为点 \(i\) 的度数,定义一棵树的方差为数组 \(d[1..n]\) 的方差。

给定 \(n\) ,求所有带标号的 \(n\) 个点的无根树的方差之和,答案对 \(998244353\) 取模。

题解

注意是方差之和,而不是方差的期望。

首先方差有个套路转化,\(\displaystyle V[x]= E[x^2] -(E[x])^2\) ,也就是平方的期望 减去期望的平方。

此处可以把期望理解成加权平均数。

至于原因?拆式子就好啦 qwq

每条边会贡献到两个点,又由于点数等于边数加一,所以就有 \(E[x] = \displaystyle \frac{2(n - 1)}{n}\) 。

那么现在只需要求 \(E[x^2]\) 的期望就好了。

如何算呢?看到 带标号无根树+度数 ,不难想到就是 \(\text{Prufer}\) 序。

\(\text{Prufer}\) 序:

一个 \(n\) 个结点的无根树,对应一个长度为 \(n − 2\) 、所有元素均为 \([1,n]\) 内整数的序列,这个序列叫 \(\text{Prufer}\) 序列。

  • 无根树 \(⇒\) \(\text{Prufer}\) 序列:删除编号最小的叶子,将其邻点编号加入数列,持续这个过程直到图中只剩 \(2\) 个点。

  • \(\text{Prufer}\) 序列 \(⇒\) 无根树:建立一个集合 \(\{1,2,...,n\}\) ,找出集合中最小的、未出现在 \(\text{Prufer}\) 序列中的元素,将其与序列首项连边,并删去这个元素和序列首项,持续这个过程直到序列为空,然后把集合中最后两个数连边。

  • 点数为 \(n\) 的无根树个数 \(=\) 长度为 \(n − 2\) 的 \(\text{Prufer}\) 序列个数 \(= n^{n−2}\)

  • 无根树中一个点的度数 \(=\) 点的编号在 \(\text{Prufer}\) 序列中出现次数 \(+1\)

我们利用最后一条性质就可以做了,考虑枚举一个点在 \(\text{Prufer}\) 序列的出现次数 \(i\) ,那么贡献就是

\[\frac{1}{n}(\sum_{i = 0}^{n - 2} {n - 2 \choose i} n (n - 1)^{n - 2 - i} (i + 1)^2)
\]

意义是十分明显的,不要忘记除掉 \(n\) ,然后就能做完了。

代码

#include <bits/stdc++.h>

#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl using namespace std; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("1511.in", "r", stdin);
freopen ("1511.out", "w", stdout);
#endif
} const int N = 1e6 + 1e3; int n, fac[N], ifac[N], Mod = 998244353; inline int fpm(int x, int power) {
int res = 1;
for (; power; power >>= 1, x = 1ll * x * x % Mod)
if (power & 1) res = 1ll * res * x % Mod;
return res;
} void Math_Init(int maxn) {
fac[0] = ifac[0] = 1;
For (i, 1, maxn) fac[i] = 1ll * fac[i - 1] * i % Mod;
ifac[maxn] = fpm(fac[maxn], Mod - 2);
Fordown (i, maxn - 1, 1) ifac[i] = ifac[i + 1] * (i + 1ll) % Mod;
} inline int Comb(int n, int m) {
if (n < 0 || m < 0 || n < m) return 0;
return 1ll * fac[n] * ifac[m] % Mod * ifac[n - m] % Mod;
} int main() { File(); n = read(); Math_Init(n); int ans = 0;
For (i, 0, n - 2)
ans = (ans + 1ll * Comb(n - 2, i) % Mod * fpm(n - 1, n - 2 - i) % Mod * (i + 1) % Mod * (i + 1)) % Mod;
int Exp = 2ll * (n - 1) * fpm(n, Mod - 2) % Mod;
Exp = 1ll * Exp * Exp % Mod * fpm(n, n - 2) % Mod;
ans = (ans - Exp + Mod) % Mod; printf ("%d\n", ans); return 0; }

HihoCoder 1511: 树的方差(prufer序)的更多相关文章

  1. LUOGU P2290 [HNOI2004]树的计数(组合数,prufer序)

    传送门 解题思路 \(prufer\)序,就是所有的不同的无根树,都可以转化为唯一的序列.做法就是每次从度数为\(1\)的点中选出一个字典序最小的,把这个点删掉,并把这个点相连的节点加入序列,直到只剩 ...

  2. hihoCoder挑战赛28 题目3 : 树的方差

    题目3 : 树的方差 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 对于一棵 n 个点的带标号无根树,设 d[i] 为点 i 的度数. 定义一棵树的方差为数组 d[1. ...

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

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

  4. bzoj1211: [HNOI2004]树的计数 prufer编码

    题目链接 bzoj1211: [HNOI2004]树的计数 题解 prufer序 可重排列计数 代码 #include<bits/stdc++.h> using namespace std ...

  5. 树的计数 Prufer序列+Cayley公式

    先安利一发.让我秒懂.. 第一次讲这个是在寒假...然而当时秦神太巨了导致我这个蒟蒻自闭+颓废...早就忘了这个东西了... 结果今天老师留的题中有两道这种的:Luogu P4981 P4430 然后 ...

  6. BZOJ 1005: [HNOI2008]明明的烦恼(高精度+prufer序)

    传送门 解题思路 看到度数和生成树个树,可以想到\(prufer\)序,而一张规定度数的图的生成树个数为\(\frac{(n-2)!}{\prod\limits_{i=1}^n(d(i)-1)!}\) ...

  7. 树的计数 + prufer序列与Cayley公式 学习笔记

    首先是 Martrix67 的博文:http://www.matrix67.com/blog/archives/682 然后是morejarphone同学的博文:http://blog.csdn.ne ...

  8. python数据结构之树和二叉树(先序遍历、中序遍历和后序遍历)

    python数据结构之树和二叉树(先序遍历.中序遍历和后序遍历) 树 树是\(n\)(\(n\ge 0\))个结点的有限集.在任意一棵非空树中,有且只有一个根结点. 二叉树是有限个元素的集合,该集合或 ...

  9. hihocoder 1391 树状数组

    #1391 : Countries 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 There are two antagonistic countries, countr ...

随机推荐

  1. Consecutive Subsequence CodeForces - 977F (map优化DP)·

    You are given an integer array of length nn. You have to choose some subsequence of this array of ma ...

  2. Java 数据库操作

    目录 Java数据库组织架构 下载驱动包 连接数据库 连接数据库的三个步骤 连接数据库的高开销 Statement接口介绍 PreparedStatement类 使用PreparedStatement ...

  3. selenium模拟登陆淘宝

    from selenium import webdriver import time from selenium.webdriver.common.by import By from selenium ...

  4. HTML中的几种空格

    HTML提供了5种空格实体(space entity),它们拥有不同的宽度,非断行空格( )是常规空格的宽度,可运行于所有主流浏览器.其他几种空格(       ‌‍)在不同浏览器中宽度各异.     ...

  5. Velocity ${} 和$!{}、!${}区别

    前言 在使用Velocity时经常会看到三种使用变量的情况 情况一:${name} 情况二:$!{name} 情况三:!${name} 那么三者之间到底有什么区别呢?莫慌!!!哈哈 情况一:${nam ...

  6. 1 Expression of Possiblity

    Expression of possibility Probably     Perhaps There's a change(that) It's very likly(that) It's pos ...

  7. [转帖]linux sed命令

    linux sed命令就是这么简单 https://www.cnblogs.com/wangqiguo/p/6718512.html 用到的最多的就是一个sed -i 's/nn/mm/' 的命令了. ...

  8. [转帖]CentOS 6 服务器安全配置指南(通用)

    CentOS 6 服务器安全配置指南(通用) http://seanlook.com/2014/09/07/linux-security-general-settings/  发表于 2014-09- ...

  9. 游标cursor案例

  10. bootstrap模态框动态赋值, ajax异步请求数据后给id为queryInfo的模态框赋值并弹出模态框(JS)

    /查询单个 function query(id) { $.ajax({ url : "/small/productServlet", async : true, type : &q ...