题意

  求 \(n\) 个点的 Treap 深度为 \(h=0,1,2,\cdots,n\) 的概率。

  Treap 是一个随机二叉树,每个节点有权值和优先级,权值和优先级都是 \([0,1]\) 中的随机实数。niubi 的是,由于随机的实数精度足够高,你可以近似认为任意两个权值、任意两个优先级相同的概率是 \(0\)。

  \(n\le 30000\)

题解

  又是神题,我他吗都做不来

  官方题解大概是这样,但本蒟蒻完全没看懂,于是只好向 scb 大佬请教了另一种思考方法(得到的 dp 式子一样)。

  考虑 Treap 的构造方式:先随机选择 \(n\) 个权值,然后从空树开始,每次插入一个节点。插入操作如下:先随机一个优先级 \(p\),无视优先级,按照二叉搜索树的方式插入这个节点,然后考虑优先级,一直把这个节点往上旋转,直到满足优先级条件。

  若我们事先确定了每个权值的优先级,那么把权值按优先级从大到小排序,不难发现 Treap 的加点就变成了每次给树加一个叶子。由于 \(n\) 个数的大小关系不变时 Treap 的形态也不变,我们可以把 \(n\) 个权值离散化成 \(1\) 到 \(n\) 这 \(n\) 个整数,问题是完全等价的。

  权值序列的每个数都不是确定的,而是在 \([0,1]\) 任取一个实数,为什么可以离散化成 \(1\) 到 \(n\) 这 \(n\) 个整数?如何证明每种 \(1\) 到 \(n\) 的排列对应的原权值序列的数量相同?(不然离散化后算的概率不一样啊)

  遗憾的是,这个需要微积分等高数知识,过程也比较复杂,本蒟蒻不会简单证法。目前把这当成常识记住就好了。

  现在优先级已经没用了,我们只需要考虑每次给树加一个权值为 \([1,n]\) 内整数的叶子,这棵树要满足二叉搜索树的性质(即任意点的权值小于其左儿子,大于其右儿子)。求每种树高的出现概率。

  这就跟普通的求方案数类似,设 \(dp(i,j)\) 表示权值为 \(1,2,\cdots j\) 的点构成深度不大于 \(i\) 的树的概率,则我们枚举根的权值 \(k\),其左子树的权值集合为 \(\{1,2,\cdots,k-1\}\),概率就是 \(dp(i-1,k-1)\);其右子树的权值集合为 \(\{k+1,k+2,\cdots,j\}\),等价于集合 \(\{1,2,\cdots,j-k\}\),概率是 \(dp(i-1,j-k)\)。把所有 \(k\) 对应的概率求平均值,就得到了 \(dp(i,j)\)。$$dp(i,j)=\frac{1}{j} \sum\limits_{k=1}^j f(i-1,k-1)\times f(i-1,j-k)$$

  \(O(n^3)\) 转移可得 \(40\) 分。

  然后发现由于权值随机,而且 Treap 本身就是在随机优先级时树高维持在 \(\log n\) 级别的数据结构,故期望树高为 \(O(\log n)\),概率都会集中在这附近。实测大概只需要算到 \(dp(50,)\) 即可满足精度要求。\(O(50n^2)\) 可得 \(50\) 分。

  然后发现上式显然是个卷积形式,把 \(dp(i)\) 看成生成函数,转移就是 \(f(i)\) 自己卷自己,\(\text{FFT}\) 即可。复杂度 \(O(50n\log n)\),可得 \(100\) 分。

#include<bits/stdc++.h>
#define N 131075
using namespace std;
inline int read(){
int x=0; bool f=1; char c=getchar();
for(;!isdigit(c); c=getchar()) if(c=='-') f=0;
for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
if(f) return x;
return 0-x;
}
int n;
const double PI = acos(-1);
struct cp{
double r,i;
cp(){r=i=0;}
cp(double _r, double _i){r=_r, i=_i;}
friend cp operator + (cp a, cp b){return cp(a.r+b.r, a.i+b.i);}
friend cp operator - (cp a, cp b){return cp(a.r-b.r, a.i-b.i);}
friend cp operator * (cp a, cp b){return cp(a.r*b.r-a.i*b.i, a.r*b.i+a.i*b.r);}
friend cp operator / (cp a, double b){return cp(a.r/b, a.i/b);}
}dp[N];
struct Poly{
int n,bit,r[N];
void init(int x){
for(n=1,bit=0; n<x; n<<=1,++bit);
for(int i=1; i<n; ++i) r[i]=(r[i>>1]>>1)|((i&1)<<(bit-1));
}
void dft(cp *a, int f){
for(int i=0; i<n; ++i) if(i<r[i]) swap(a[i],a[r[i]]);
cp wn,w,x,y;
for(int i=1; i<n; i<<=1){
wn=cp(cos(PI/i),sin(f*PI/i));
for(int j=0; j<n; j+=i<<1){
w=cp(1,0);
for(int k=0; k<i; ++k,w=w*wn)
x=a[j+k], y=w*a[j+i+k],
a[j+k]=x+y, a[j+i+k]=x-y;
}
}
if(f==-1) for(int i=0; i<n; ++i) a[i]=a[i]/n;
}
}FFT;
int main(){
n=read();
FFT.init(n*2+1);
dp[0]=cp(1,0); double lst=0;
for(int scx=1; scx<=min(n,50); ++scx){
FFT.dft(dp,1);
for(int i=0; i<FFT.n; ++i) dp[i]=dp[i]*dp[i];
FFT.dft(dp,-1);
for(int i=n; i<FFT.n; ++i) dp[i]=cp(0,0);
for(int i=n; i>0; --i) dp[i]=dp[i-1]/i; dp[0]=cp(1,0);
printf("%.10lf\n",dp[n].r-lst);
lst=dp[n].r;
}
for(int i=min(n,50)+1; i<=n; ++i) printf("%.10lf\n",0);
return 0;
}

【未知来源】Randomized Binary Search Tree的更多相关文章

  1. 【XSY2332】Randomized Binary Search Tree 概率DP FFT

    题目描述 \(\forall 0\leq i<n\),求有多少棵\(n\)个点,权值和优先级完全随机的treap的树高为\(i\). \(n\leq 30000\) 题解 设\(f_{i,j}\ ...

  2. 【xsy2332】Randomized Binary Search Tree DP+FFT

    题目大意:给你一个$[0,1]$之间等概率随机序列,你需要把这个序列插入到一棵$treap$中,问这棵$treap$的期望深度,请对于$[1,n]$中的每个深度分别输出它的概率(实数,保留五位小数). ...

  3. [LeetCode]题解(python):098 Validate Binary Search Tree

    题目来源 https://leetcode.com/problems/validate-binary-search-tree/ Given a binary tree, determine if it ...

  4. 一道二叉树题的n步优化——LeetCode98validate binary search tree(草稿)

    树的题目,往往可以用到三种遍历.以及递归,因为其结构上天然地可以往深处递归,且判断条件也往往不复杂(左右子树都是空的). LeetCode 98题讲的是,判断一棵树是不是二叉搜索树. 题目中给的是标准 ...

  5. 【LeetCode】 99. Recover Binary Search Tree [Hard] [Morris Traversal] [Tree]

    Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing ...

  6. Lowest Common Ancestor of a Binary Search Tree(树中两个结点的最低公共祖先)

    题目描述: Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in ...

  7. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  8. Leetcode 笔记 99 - Recover Binary Search Tree

    题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...

  9. Leetcode 笔记 98 - Validate Binary Search Tree

    题目链接:Validate Binary Search Tree | LeetCode OJ Given a binary tree, determine if it is a valid binar ...

随机推荐

  1. 【VS开发】recv函数函数返回值说明(特别有利于工程调试)

    recv函数 int recv( SOCKET s, char FAR *buf, int len, int flags); 不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据. ...

  2. 今盒子里有n个小球,A、B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个

    /* 题目描述 今盒子里有n个小球,A.B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断. 我们约定: 每个人从盒子中取出的球 ...

  3. My life

    突然想到的好笑的: 1. 世界上一共有10种人,一种是男人,另一种是女人 2. 吐槽一个网站的域名: 你这网站域名取得,跟色情网站似的 明知这是一场意外,你要不要来,明知这是一场重伤害,你会不会来: ...

  4. POJ1041 John's trip 【字典序输出欧拉回路】

    题目链接:http://poj.org/problem?id=1041 题目大意:给出一个连通图,判断是否存在欧拉回路,若存在输出一条字典序最小的路径. 我的想法: 1.一开始我是用结构体记录边的起点 ...

  5. Appendix 1- LLN and Central Limit Theorem

    1. 大数定律(LLN) 设Y1,Y2,……Yn是独立同分布(iid,independently identically distribution)的随机变量,A = SY /n = (Y1+...+ ...

  6. 点了安装SQL2000后没反应了的处理方法

    摘自JerrY的博客 http://blog.sina.com.cn/s/blog_403ef7e80101iy3p.html 点了安装SQL2000后没反应了的处理方法 以前的时候给客户电脑安装SQ ...

  7. gRPC 本地服务搭建

    RPC RPC 原理 主流 RPC 框架 gRPC 概述 特点 服务端创建 定义服务 生成 gRPC 代码 服务端实现 客户端实现 踩坑记录 源码 RPC RPC 原理 RPC 框架的目标就是让远程服 ...

  8. python-面向对象速查表-内置方法-内置函数-内置属性(只整理了部分内容)

    今日临时总结的内容,可能还有些不正确的地方,初步当做个速查表吧. 类的内置函数(继承object的,自己重写) 内置函数 执行时机 注意点 调用案例 __init__ 实例化对象时 不允许写返回值(r ...

  9. 开始写下自己的python的cocos2d, pyglet学习

    开始写下自己的python的cocos2d, pyglet学习 2014年01月18日 13:52:36 我要做程序达人 阅读数 9051更多 分类专栏: python的cocos2d和pyglet ...

  10. gRPC 和 C#

    前些天gRPC 发布1.0 版本,代表着gRPC 已经正式进入稳定阶段. 今天我们就来学习gRPC C# .而且目前也已经支持.NET Core 可以实现完美跨平台. 传统的.NET 可以通过Mono ...