题意

你有一棵 \(n\) 个点的树,每次会随机选择树上的一条边,将两个端点 \(u,v\) 合并,新编号随机为 \(u,v\)。问最后保留的编号分别为 \(1\) 到 \(n\) 的概率。

\(n\leq 50\) 。

分析

  • 考虑枚举钦定一个编号为 \(ans\) 之后以他为根跑一次树dp。

  • 思考一下操作的执行过程。首先,操作连接 \(rt\) 和他的儿子 \(v\) 的边时,必须保留 \(rt\) 的编号,然后合并掉 \(v\) ,可以看成是 \(rt\) 将他的编号传递给了 \(v\) (\(rt\) 变成了一个大点)。那么此时对于 \(v\) 子树内的编号变化就是一个子问题了。

  • 记 \(f_{u,i}\) 表示当 \(rt\) 下放到 \(u\) 时, \(u\) 的子树边还有 \(i\) 条没有合并,所有删边方案最后保留 \(rt\) 的概率和。

    记 \(g_{u,i}\) 表示当 \(rt\) 下放到 \(u\) 的父亲时, \(u\) 的子树边+返祖边还有 \(i\) 条没有合并,所有删边方案最后保留 \(rt\) 的概率和。

  • 考虑合并 \(u\) 的儿子 \(v\) , \(u \rightarrow v\) 这条边可以在 2 个不同的时间段合并。

1.在编号下放到 \(u\) 之后。假设下放到 \(u\) 时 \(v\) 子树内有 \(x\) 条边,那么在删除 \(u \rightarrow v\) 之后 \(v\) 的子树内有 \(\leq x\) 条边,所以 \(g_{v,x}+=0.5*\sum_{i=0}^{min({son}_v-1,x)}f_{v,i}\) ,因为此时保留 \(rt\) 的概率是 \(0.5\) 。

2.在编号下放到 \(u\) 之前。所以下放到 \(u\) 时 \(u\) 和 \(v\) 已经看成是一个点,等价于下放到 \(v\) 。\(u \rightarrow v\) 可以在删除 \(v\) 子树内的 \({son}_v-1-x\) 条边中的任何空隙删除,所以 \(g_{v,x}+=f_{v,x}*({son}_v-x)\) 。

  • 考虑儿子 \(x\) 和 \(y\) 之间的合并,发现他们之间的删边顺序互不影响,容易得到:

\[f_{u,i}=\sum_{a=0}^{{son}_x}\sum_{b=0}^{{son}_y}g_{x,a}*g_{y,b}*\binom{a+b}{a}\binom{{son}_x-a+{son}_y-b}{{son}_x-a}
\]

  • 最后的答案除以 \((n-1)!\) 即可。

  • 总时间复杂度为 \(O(n^4)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].lst,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
typedef double db;
const int N=54;
int n,edc;
int head[N],son[N];
db f[N][N],fac[N],g[N];
struct edge{
int lst,to;
edge(){}edge(int lst,int to):lst(lst),to(to){}
}e[N*2];
void Add(int a,int b){
e[++edc]=edge(head[a],b),head[a]=edc;
e[++edc]=edge(head[b],a),head[b]=edc;
}
db C(int n,int m){
return fac[n]/fac[m]/fac[n-m];
}
void dfs(int u,int fa){
f[u][0]=1;son[u]=1;
go(u)if(v^fa){
dfs(v,u);int tot=son[u]-1+son[v];
fill(g,g+tot+1,0);
for(int a=son[u]-1;~a;--a)
for(int b=son[v];~b;--b)
g[a+b]+=f[u][a]*f[v][b]*C(a+b,a)*C(tot-a-b,son[v]-b);
son[u]+=son[v];
rep(a,0,son[u]-1) f[u][a]=g[a];
}
if(fa){
fill(g,g+son[u]+1,0);
for(int a=son[u]-1;~a;--a){
g[a]+=f[u][a]*(son[u]-a);
for(int b=a+1;b<=son[u];++b)
g[b]+=f[u][a]*0.5;
}
rep(a,0,son[u]) f[u][a]=g[a];
}
}
int main(){
n=gi();
rep(i,1,n-1) Add(gi(),gi());
fac[0]=1;
rep(i,1,n) fac[i]=fac[i-1]*i;
rep(i,1,n){
memset(f,0,sizeof f);
dfs(i,0);
printf("%.10lf\n",f[i][n-1]/fac[n-1]);
}
return 0;
}

[CF1060F]Shrinking Tree[树dp+组合计数]的更多相关文章

  1. 牛客国庆集训派对Day3 B Tree(树形dp + 组合计数)

    传送门:https://www.nowcoder.com/acm/contest/203/B 思路及参考:https://blog.csdn.net/u013534123/article/detail ...

  2. 3.29省选模拟赛 除法与取模 dp+组合计数

    LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采 ...

  3. HDU 4359——Easy Tree DP?——————【dp+组合计数】

    Easy Tree DP? Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  4. [CF1060F]Shrinking Tree

    description codeforces 给一棵\(n\)个节点的树,每次等概率选择树中剩下边的一条进行缩边,这条边的两个端点有相同的概率被保留,求最后每个点被留下的概率. data range ...

  5. Codeforces 161 D. Distance in Tree (树dp)

    题目链接:http://codeforces.com/problemset/problem/161/D 题意: 给你一棵树,问你有多少对点的距离为k. 思路: dp[i][j]表示离i节点距离为j的点 ...

  6. ZOJ-3380 Patchouli’s Spell Cards DP, 组合计数

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3380 题意:有m种不同的元素,每种元素都有n种不同的相位,现在假 ...

  7. BZOJ4517 Sdoi2016 排列计数 【DP+组合计数】*

    BZOJ4517 Sdoi2016 排列计数 Description 求有多少种长度为 n 的序列 A,满足以下条件: 1 ~ n 这 n 个数在序列中各出现了一次 若第 i 个数 A[i] 的值为 ...

  8. bzoj 2425 [HAOI2010]计数 dp+组合计数

    [HAOI2010]计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 451  Solved: 289[Submit][Status][Discus ...

  9. URAL1018 Binary Apple Tree(树dp)

    组队赛的时候的一道题,那个时候想了一下感觉dp不怎么好写呀,现在写了出来,交上去过了,但是我觉得我还是应该WA的呀,因为总感觉dp的不对. #pragma warning(disable:4996) ...

随机推荐

  1. LeeTCode题解之Remove Duplicates from Sorted List

    1.题目描述 2.问题分析 对于链表中的每一个元素,找到其后面和它不相等的第一个元素,然后指向该元素. 3.代码 ListNode* deleteDuplicates(ListNode* head) ...

  2. 《SQLSERVER2012实施与管理实战指南》前4章节笔记内容

    <SQLSERVER2012实施与管理实战指南>前4章节笔记内容 <SQLSERVER2012实施与管理实战指南>的前面4章是<SQLSERVER企业级平台管理实践> ...

  3. Oracle Dynamic Performance Views Version 12.2.0.1

    Oracle Dynamic Performance ViewsVersion 12.2.0.1 https://www.morganslibrary.org/reference/dyn_perf_v ...

  4. Access restriction: The type BASE64Encoder is not accessible due to restriction on required library C:\Program Files\Java\jre6\lib\rt.jar

    解决方案:在configure build path 中去掉 jre system library,然后重新加载jre system library.....

  5. FastDFS_v5.05+nginx+cache集群安装配置手册

    转载请出自出处:http://www.cnblogs.com/hd3013779515/ 1.FastDFS简单介绍 FastDFS是由淘宝的余庆先生所开发,是一个轻量级.高性能的开源分布式文件系统, ...

  6. 10行代码爬取全国所有A股/港股/新三板上市公司信息

    摘要: 我们平常在浏览网页中会遇到一些表格型的数据信息,除了表格本身体现的内容以外,可能还想透过表格背后再挖掘些有意思或者有价值的信息.这时,可用python爬虫来实现.本文采用pandas库中的re ...

  7. 【Lucene4.8教程之六】QueryParser与Query子类:怎样生成Query对象

    版权声明:本文为博主原创文章.转载请注明来自http://blog.csdn.net/jediael_lu/ https://blog.csdn.net/jediael_lu/article/deta ...

  8. win10管理员已阻止你运行此应用”解决方法

    方法/步骤 1 按WIN+R键,打开“运行”,然后输入“gpedit.msc",就是打开组策略,这个在控制面板中也可以打开. 2 在组策略里找到“计算机配置”-“Windows设置”-“安全 ...

  9. php api接口安全设计 sign理论

    一. url请求的参数包括:timestamp,token, username,sign 1. timestamp: 时间戮 2. token: 登陆验证时,验证成功后,生成唯一的token(可以为u ...

  10. String----是一个对象

    * 字符串可以看成是字符组成的数组,但是js中没有字符类型 * 字符是一个一个的,在别的语言中字符用一对单引号括起来 * 在js中字符串可以使用单引号也可以使用双引号 * 因为字符串可以看成是数组,所 ...