\(\mathcal{Description}\)

  Link.

  给定一棵 \(n\) 个点的树,反复随机选取一条边,合并其两端两点,新点编号在两端两点等概率选取。问每个点留到最后的概率。

  \(n\le50\)。

\(\mathcal{Solution}\)

  推荐 @ywy_c_asm博客 owo。

  所有的操作方案数是 \((n-1)!\),我们可以按删边顺序看做一个长度为 \(n-1\) 的序列。对于每个点分别计算答案,把当前要算的点提为根(记为 \(r\)),我们只需要求出 \(r\) 在所有操作序列中存活的概率和除以 \((n-1)!\) 即可。

  令 \(f(u,i)\) 为 \(r\) 已经走到 \(u\),\(u\) 子树内还剩下 \(i\) 条边没删(没加入删边序列),最终 \(u\)(即 \(r\))存活的概率和。显然答案为 \(f(r,n-1)\),边界 \(f(leaf,0)=1\)。


  第一步,考虑儿子 \(v\) 与 \(u\) 合并。相当于需要考虑边 \((u,v)\) 在操作序列中的位置。粗略来说,若 \(r\) 没走到 \(u\),我们并不关心 \(u\) 号结点的生死;而 \(r\) 到 \(u\) 后,\(u\) 就必须存活。

  定义辅助状态 \(g(u,i)\) 表示 \(u\) 子树内以及 \(u\) 的父边还剩下 \(i\) 条边没删,最终 \(u\) 存活的概率和。现在我们要计算 \(g(u,i)\)。

  第一类,\((u,v)\) 保留到 \(r\) 到达 \(u\) 后再删,那么就涉及到 \(u\) 点存活的概率。于是有转移:

\[g(u,i)=\frac{1}2\sum_{v\in son_u\land j\in[0,i)}f(v,j)
\]

  第二类,\((u,v)\) 在 \(r\) 到达 \(u\) 之前就删,那就很随意啦—— \(v\) 子树中已删除了 \(siz_v-1-i\) 条边,我们把 \((u,v)\) 随便插进一个位置就好,即:

\[g(u,i)=(siz_v-i)f(v,i)
\]

  上两类转移贡献之和即为最终的 \(g(u,i)\)。


  考虑合并,始终记住删除的“序列意义”——保留的边(状态第二维)在删边序列的右端,其它的边在删边序列的左端。合并两个删边序列,仍需要保证这一点,那么分别用组合数合并已删除的左端序列和待删除的右端序列即可。下是 @ywy_c_asm 博客的一张图 owo(红色已删除,蓝色待删除):

  答案呼之欲出啦:

\[f'(u,i+j)=\sum_{i,j}\binom{i+j}{i}\binom{(siz_u-1)+siz_v-i-j}{(siz_u-1)-i}f(u,i)g(v,j)
\]

  两个组合数分别对应分配已删和待删的方案数。

  最终,复杂度 \(\mathcal O(n^4)\) 解决了这道毒瘤 DP qwq。

\(\mathcal{Code}\)

  1. #include <cstdio>
  2. #include <cstring>
  3. const int MAXN = 50;
  4. int n, ecnt, head[MAXN + 5], siz[MAXN + 5];
  5. double fac[MAXN + 5];
  6. double f[MAXN + 5][MAXN + 5];
  7. double g[MAXN + 5], h[MAXN + 5];
  8. struct Edge { int to, nxt; } graph[MAXN * 2 + 5];
  9. inline void link ( const int s, const int t ) {
  10. graph[++ ecnt] = { t, head[s] };
  11. head[s] = ecnt;
  12. }
  13. inline void init () {
  14. fac[0] = 1;
  15. for ( int i = 1; i <= n; ++ i ) fac[i] = fac[i - 1] * i;
  16. }
  17. inline double comb ( const int n, const int m ) {
  18. return n < m ? 0 : fac[n] / fac[m] / fac[n - m];
  19. }
  20. inline void solve ( const int u, const int fa ) {
  21. f[u][0] = siz[u] = 1;
  22. for ( int i = head[u], v; i; i = graph[i].nxt ) {
  23. if ( ( v = graph[i].to ) ^ fa ) {
  24. solve ( v, u );
  25. for ( int j = 0; j <= siz[v]; ++ j ) {
  26. g[j] = 0;
  27. for ( int k = 0; k < j; ++ k ) g[j] += 0.5 * f[v][k];
  28. g[j] += ( siz[v] - j ) * f[v][j];
  29. }
  30. for ( int j = 0; j <= siz[v] + siz[u]; ++ j ) h[j] = 0;
  31. for ( int j = 0; j < siz[u]; ++ j ) {
  32. for ( int k = 0; k <= siz[v]; ++ k ) {
  33. h[j + k] += f[u][j] * g[k] * comb ( j + k, j )
  34. * comb ( siz[u] + siz[v] - 1 - j - k, siz[u] - 1 - j );
  35. }
  36. }
  37. siz[u] += siz[v];
  38. for ( int j = 0; j <= siz[u]; ++ j ) f[u][j] = h[j];
  39. }
  40. }
  41. }
  42. int main () {
  43. scanf ( "%d", &n ), init ();
  44. for ( int i = 1, u, v; i < n; ++ i ) {
  45. scanf ( "%d %d", &u, &v );
  46. link ( u, v ), link ( v, u );
  47. }
  48. for ( int i = 1; i <= n; ++ i ) {
  49. memset ( f, 0, sizeof f );
  50. solve ( i, 0 );
  51. printf ( "%.12f\n", f[i][n - 1] / fac[n - 1] );
  52. }
  53. return 0;
  54. }

Solution -「CF 1060F」Shrinking Tree的更多相关文章

  1. Solution -「CF 1491H」Yuezheng Ling and Dynamic Tree

    \(\mathcal{Description}\)   Link. 做题原因:题目名.   给定一个长度 \(n-1\) 的序列 \(\{a_2,a_3,\cdots,a_n\}\),其描述了一棵 \ ...

  2. Solution -「CF 1375G」Tree Modification

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个结点的树,每次操作选择三个结点 \(a,b,c\),满足 \((a,b),(b,c)\in E\),并令 ...

  3. Solution -「CF 1342E」Placing Rooks

    \(\mathcal{Description}\)   Link.   在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...

  4. Solution -「CF 1237E」Balanced Binary Search Trees

    \(\mathcal{Description}\)   Link.   定义棵点权为 \(1\sim n\) 的二叉搜索树 \(T\) 是 好树,当且仅当: 除去最深的所有叶子后,\(T\) 是满的: ...

  5. Solution -「CF 494C」Helping People

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\) 和 \(m\) 个操作,第 \(i\) 个操作有 \(p_i\) 的概率将 \([l_i,r_ ...

  6. Solution -「CF 793G」Oleg and Chess

    \(\mathcal{Description}\)   Link.   给一个 \(n\times n\) 的棋盘,其中 \(q\) 个互不重叠的子矩阵被禁止放棋.问最多能放多少个互不能攻击的车.   ...

  7. Solution -「CF 1622F」Quadratic Set

    \(\mathscr{Description}\)   Link.   求 \(S\subseteq\{1,2,\dots,n\}\),使得 \(\prod_{i\in S}i\) 是完全平方数,并最 ...

  8. Solution -「CF 923F」Public Service

    \(\mathscr{Description}\)   Link.   给定两棵含 \(n\) 个结点的树 \(T_1=(V_1,E_1),T_2=(V_2,E_2)\),求一个双射 \(\varph ...

  9. Solution -「CF 923E」Perpetual Subtraction

    \(\mathcal{Description}\)   Link.   有一个整数 \(x\in[0,n]\),初始时以 \(p_i\) 的概率取值 \(i\).进行 \(m\) 轮变换,每次均匀随机 ...

随机推荐

  1. mysql 的 if 和 SQL server 的 iif

    在sql语句中,mysql 使用 if 而SQL server 使用iif 如 mysql : SELECT IF(1<2,'yes ','no'); sql server: SELECT II ...

  2. win10中查看开关机时间及查看admin的RID的方法

    原文链接: https://www.toutiao.com/i6772133439593251339/ 打开系统的注册表 键盘输入win+r组合键出现运行窗口命令 输入regedit 按回车键,进入注 ...

  3. 一文搞懂Flink Window机制

    Windows是处理无线数据流的核心,它将流分割成有限大小的桶(buckets),并在其上执行各种计算. 窗口化的Flink程序的结构通常如下,有分组流(keyed streams)和无分组流(non ...

  4. Nginx 基础入门

    目录 Nginx 基础入门 1.Nginx简介 1.1.相关名词解释 2.Nginx优势 3.Nginx部署 4.Nginx配置文件 5.Nginx模块 6.Nginx配置文件 6.1.Locatio ...

  5. sql创建表格时出现乱码

    1.新建数据库时,第一次只填写了数据库名称保存数据库,如下图: 2.创建一个Student表格,代码如下,其中有数据有中文,创建完后查看表格数据,发现中文为乱码 create table Studen ...

  6. spring是线程安全的吗

    spring默认bean是单例无状态的,我们交给spring管理的service,controller都是一个单例的bean,也就是说多个线程共享一个实例. 如果你在这种类里写成员变量,那这个变量的访 ...

  7. Xbatis:SpringBoot 数据管理框架

    目录 安装 下载源码 编译源码 添加依赖 数据表 数据源 Xbatis XbatisManager Database/Table/Column Column Table Database Create ...

  8. 【记录一个问题】android ndk中不支持pthread_yield()

    如题 使用这个函数报如下错误: error: use of undeclared identifier 'pthread_yield' pthread_yield(); 不得已,使用usleep(50 ...

  9. MyCms 开源自媒体系统,系统配置字段说明

    功能说明 站点名称:站点的简要描述名称,没有启用SEO插件时,将用此字段用作站点标题. 站点地址:站点的完整地址(包含 http/https),此字段有多处依赖用于生成链接,请正确填写. 站点logo ...

  10. Servlet-请求转发

    Servlet-请求转发 请求转发:服务器收到请求后,从一个资源跳转到另一个资源的操作叫请求转发 请求转发特点: 1,浏览器地址栏没有变化 2,他们是一次请求 3,他们共享Request域中的数据 4 ...