码迷,mamicode.com
首页 > 其他好文 > 详细

Kattis - heapsoffun Heaps of Fun (概率密度函数+dp)

时间:2019-08-22 12:58:37      阅读:111      评论:0      收藏:0      [点我收藏+]

标签:方法   需要   ant   最小堆   std   随机   def   sizeof   tor   

题意:有一棵含有n个结点(n<=300)的根树,树上每个结点上的权值是从[0,ai](ai<=1e9)区间内随机的一个实数,问这棵树能形成一个最小堆的概率。

由于结点取值范围是1e9而且是实数,所以枚举权值dp自然是行不通的了,但可以从函数的角度上考虑。

首先需要了解两个概念:

CDF:分布函数,记为F(x),表示函数F的取值小于等于x的概率。

PDF:概率密度函数,记为f(x),是F(x)的导数,反之,F(x)是f(x)在区间(-∞,x]上的积分。由于本题所有的取值都是从0开始的,因此也可以表示在区间[0,x]上的积分。

那么答案就是根节点rt所对应的CDF的上界Frt(+∞)。

我们记fu(x)为结点u的取值的PDF,Fu(x)为其CDF,那么对于每个叶子结点u来说:

$f_u(x)=\left\{\begin{matrix}\begin{aligned}&\frac{1}{a[u]},0\leqslant x\leqslant a[u]\\&0,others\end{aligned}\end{matrix}\right.,F_u(x)=\int_{0}^{x}f_u(t)dt=\left\{\begin{matrix}\begin{aligned}&\frac{1}{a[u]}x,0\leqslant x\leqslant a[u]\\&1,x>a[u]\end{aligned}\end{matrix}\right.$

那么有了子结点的PDF和CDF,如何去求父结点的PDF和CDF呢?

首先我们要算出每个子结点的取值大于x的概率,因为如果结点u的某个取值x是合法的,那么它的所有子节点的取值都必须大于x。既然Fu(x)表示结点u取值小于等于x的概率,那么取值大于x的概率呢?是1-Fu(x)吗?No!这个公式只适用于叶子结点,因为这里的Fu(x)表示的是“该结点所在子树满足最小堆性质且该结点的值小于等于x的概率”,因此Fu的上界不一定为1,也就是说x的所有取值的概率之和不一定为1。那么应该如何计算呢?

设ub[u]表示结点u及子树下的所有结点的最小的a,那么显然结点u的取值不能超过ub[u],即ub[u]是结点u取值的上界。

所以,正确的计算方法是结点u取值大于x的概率$G_u(x)=\left\{\begin{matrix}\begin{aligned}&F(ub[u])-F(x),0\leqslant x\leqslant ub[u]\\&0,x>ub[u]\end{aligned}\end{matrix}\right.$

有了子结点的G,就可以求父结点的f了,通过概率计算公式可得:

$f_u(x)=\frac{1}{a[u]}\prod\limits_{fa[v]=u}F‘_v(x)$

然后对fu(x)积分可以得到Fu(x),然后又可以求出Gu(x),之后就可以继续往父结点递推了。最终答案就是根节点的G(x)的常数项。

代码如下:(为了方便,代码中每个结点最后保存的函数是G(x))

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=300+10,mod=1e9+7;
 5 int hd[N],ne,rt,a[N],n,ub[N];
 6 struct E {int v,nxt;} e[N];
 7 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
 8 int Pow(int x,int p) {
 9     int ret=1;
10     for(; p; p>>=1,x=(ll)x*x%mod)if(p&1)ret=(ll)ret*x%mod;
11     return ret;
12 }
13 int inv(int x) {return Pow(x,mod-2);}
14 typedef vector<int> Poly;
15 Poly F[N];
16 Poly operator*(Poly& a,Poly& b) {
17     Poly c(a.size()+b.size()-1,0);
18     for(int i=0; i<a.size(); ++i)
19         for(int j=0; j<b.size(); ++j)
20             c[i+j]=(c[i+j]+(ll)a[i]*b[j])%mod;
21     return c;
22 }
23 Poly itg(Poly& a) {
24     Poly c(a.size()+1,0);
25     for(int i=0; i<a.size(); ++i)c[i+1]=(ll)a[i]*inv(i+1)%mod;
26     return c;
27 }
28 int eval(Poly& a,int x) {
29     int ret=0;
30     for(int i=a.size()-1; i>=0; --i)ret=((ll)ret*x+a[i])%mod;
31     return ret;
32 }
33 void dfs(int u) {
34     ub[u]=a[u],F[u].push_back(inv(a[u]));
35     for(int i=hd[u]; ~i; i=e[i].nxt) {
36         int v=e[i].v;
37         dfs(v),ub[u]=min(ub[u],ub[v]),F[u]=F[u]*F[v];
38     }
39     F[u]=itg(F[u]),F[u][0]=eval(F[u],ub[u]);
40     for(int i=1; i<F[u].size(); ++i)F[u][i]=-F[u][i];
41 }
42 int main() {
43     memset(hd,-1,sizeof hd),ne=0;
44     scanf("%d",&n);
45     for(int i=1,f; i<=n; ++i) {
46         scanf("%d%d",&a[i],&f);
47         if(f)addedge(f,i);
48         else rt=i;
49     }
50     dfs(rt);
51     printf("%d\n",(F[rt][0]+mod)%mod);
52     return 0;
53 }

 

Kattis - heapsoffun Heaps of Fun (概率密度函数+dp)

标签:方法   需要   ant   最小堆   std   随机   def   sizeof   tor   

原文地址:https://www.cnblogs.com/asdfsag/p/11393081.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!