【BZOJ3244】树的计数(NOI2013)-概率期望+数学证明

测试地址:树的计数
做法:本题需要用到概率期望+数学证明。
要求树的期望高度,我们知道树的BFS的层数就是它的高度,所以我们要对BFS序分层。但由于有DFS序的限制,我们需要更加深入地考虑DFS序对BFS序的限制。为了方便,我们把BFS序映射成 1,..,n 1 , . . , n ,并对应地修改DFS序。
首先,显然BFS序的一种划分方案要么不合法,要么和一种满足要求的树一一对应。
然后,由于题目中的条件:一个点的儿子在DFS序中出现的顺序和在BFS中出现的顺序相同,所以BFS序中同一层的点出现的顺序应该和DFS序中出现的顺序相同。我们把这称为条件一。
接下来,DFS序中相邻的两个点 u,v u , v v v 要么是u的某个祖先的儿子,要么是 u u 的儿子,那么我们有depth(u)+1depth(v)。我们把这称为条件二。
那么我们考虑对BFS序分层,实际上就是考虑在哪些间隙添加断点,那么期望层数就是期望断点数 +1 + 1 。首先在 1 1 后面是肯定要分层的,然后因为条件一的限制,如果两个在BFS序中相邻的点u,v中, u u 在DFS序中的出现位置比v的出现位置靠后,那么这两个点就不能被分在同一层中,它们中间必须有一个断点。再考虑条件二,我们可以把不等式写成 depth(v)depth(u)1 d e p t h ( v ) − d e p t h ( u ) ≤ 1 ,也就是说,如果 u u 在BFS序中在v之前,那么它们之间至多只能有一个断点,否则它们的深度差就会超过 1 1 。我们用已经确定必须要断的点来更新这种情况,即如果一个限制区间中已经有断点,那么限制区间中的其它点就不能断,这个可以用类似差分的标记方法解决。而对于没有断点的限制区间,可以证明这样的区间包含的间隙数目只可能为1(证明见下面的补证),那么这个点有 12 1 2 的概率是断点。根据期望的线性性,我们直接把每个间隙是断点的概率相加,就是期望断点数,再加上 1 1 就是期望层数,也就是树的期望高度了,时间复杂度为O(n)
补一个小证明:不包含断点的限制区间包含的间隙数只能是 1 1 。使用反证法,假设它包含的间隙数大于1,因为区间内不包含由条件一得到的断点,所以区间内的点在DFS序中出现的顺序应该和在BFS序中出现的顺序相同,但是一个限制区间是由DFS序中相邻两个点确定的,这样就无论如何都不能使得这些点在DFS序中和在BFS序中出现的顺序相同,矛盾,所以待证结论必然成立。
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
int n,dfs[200010],p[200010];
int pos[200010],type[200010]={0},sum[200010],tag[200010]={0};
double ans=1.0;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&dfs[i]);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        p[x]=i;
    }
    for(int i=1;i<=n;i++)
    {
        dfs[i]=p[dfs[i]];
        pos[dfs[i]]=i;
    }

    sum[0]=0;
    for(int i=1;i<n;i++)
    {
        if (i==1||pos[i]>pos[i+1])
            type[i]=1;
        sum[i]=sum[i-1]+type[i];
    }
    for(int i=1;i<n;i++)
        if (dfs[i]<dfs[i+1]&&sum[dfs[i+1]-1]-sum[dfs[i]-1]>0)
        {
            tag[dfs[i]]++;
            tag[dfs[i+1]]--;
        }

    int now=0;
    for(int i=1;i<n;i++)
    {
        now+=tag[i];
        if (!type[i]&&now) type[i]=2;
    }
    for(int i=1;i<n;i++)
    {
        if (type[i]==1) ans+=1.0;
        if (!type[i]) ans+=0.5;
    }
    printf("%.3lf",ans);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值