【题解】Heaps of Fun (概率论)

【题解】Heaps of Fun (概率论)

看完题解才发现讲题的时候讲的是什么屎,你说的分段是指分两段吗.......

简要题意:

给定你一棵树(不一定是二叉树),每个点有个随机点权,在\([0,a[u]]\)均匀分布,问你这棵树满足堆性质(小根堆)的概率是多少?

取值如果是整数可以直接DP,但是如果是实数怎么办?

每个节点搞一个随机变量\(X_u\),满足\(P(X_u=x)\)表示这个节点是\(x\)的时候的满足条件的概率,概率分布函数和概率密度函数分别记为\(F_u(x),f_u(x)\),定义查百度,特别提醒\(F_u(x)=\sum_{t\le x} P(X_u=t)\)是前缀,而\(\int f(x)\mathrm dx=F(x)+0\)

边界条件很好办,不论咋样都是合法的,但是怎么转移呢??

假若\(X_u=x\),那么如果要合法,就要保证\(X_{son[u]}< x\),而这个概率就是\(F_{son[u]}(x)\)(因为概率分布函数是连续的),所以

\[P(X_u=x)={1\over a[u]}\prod_{v\in son[u]} P(X_v>x) \]

但是\(X\)是连续的随机变量,我们只能通过\(F,f\)来转移。设\(low[x]\)表示\(x\)子树内最小的\(a[u]\)值,那么这个值是最小满足条件(合法且在定义域内)的值(实际上取不到,只能无限接近),所以\(P(X_x>t)=F(low[x])-F(t)\)。设\(=h_u(x)\)

根据一些前置姿势(概率论与数理统计上有),\(f_x(t)=P(X_x=t)\),根据书上的关系就有\(F(x)=\int f(x)\),那么直接积分一下就好了

答案是\(h_{rt}(+\inf)=F_{rt}[0]\)

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;  typedef long long ll; 
inline int qr(){
	int ret=0,f=0,c=getchar();
	while(!isdigit(c))f|=c==45,c=getchar();
	while(isdigit(c)) ret=ret*10+c-48,c=getchar();
	return f?-ret:ret;
}
typedef vector<int> poly;
const int mod=1e9+7;
const int maxn=3e2+5;
poly f[maxn],e[maxn];
int low[maxn],a[maxn],n,rt;
int MOD(const int&x){return x>=mod?x-mod:x;}
int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
poly operator * (poly a,poly b){
	if(a.empty()||b.empty()) return poly();
	poly ret(a.size()+b.size()-1,0);
	for(int t=0,ed=a.size();t<ed;++t)
		for(int i=0,ed=b.size();i<ed;++i)
			ret[t+i]=MOD(ret[t+i]+MOD(a[t],b[i]));
	return ret;
}
int ksm(const int&ba,const int&p){
	int ret=1;
	for(int t=p,b=ba;t;t>>=1,b=1ll*b*b%mod)
		if(t&1) ret=1ll*ret*b%mod;
	return ret;
}
void Int(poly&x){
	if(x.empty()) return;
	x.resize(x.size()+1);
	for(int t=x.size()-1;t;--t)
		x[t]=MOD(x[t-1],ksm(t,mod-2));
	x[0]=0;
}
int F(const poly&x,int g){
	int ret=0;
	for(int t=x.size()-1;~t;--t)
		ret=MOD(MOD(ret,g)+x[t]);
	return ret;	
}
void add(int fr,int to){e[fr].push_back(to);}
void dfs(int now){
	low[now]=a[now]; f[now].resize(1,1);
	for(auto t:e[now])
		dfs(t),low[now]=min(low[now],low[t]),f[now]=f[now]*f[t];
	f[now]=f[now]*(poly){ksm(a[now],mod-2)};
	Int(f[now]); f[now][0]=F(f[now],low[now]);
	for(int t=1,ed=f[now].size();t<ed;++t) f[now][t]=MOD(mod-f[now][t]);
}

int main(){
	n=qr();
	for(int t=1;t<=n;++t){
		a[t]=qr();
		int fa=qr();
		if(fa) add(fa,t);
		else rt=t;
	}
	dfs(rt);
	printf("%d\n",f[rt][0]);
	return 0;
}


posted @ 2020-04-15 15:32  谁是鸽王  阅读(424)  评论(0编辑  收藏  举报