zoukankan      html  css  js  c++  java
  • 【BZOJ3244】树的计数(NOI2013)-概率期望+数学证明

    测试地址:树的计数
    做法:本题需要用到概率期望+数学证明。
    要求树的期望高度,我们知道树的BFS的层数就是它的高度,所以我们要对BFS序分层。但由于有DFS序的限制,我们需要更加深入地考虑DFS序对BFS序的限制。为了方便,我们把BFS序映射成1,..,n,并对应地修改DFS序。
    首先,显然BFS序的一种划分方案要么不合法,要么和一种满足要求的树一一对应。
    然后,由于题目中的条件:一个点的儿子在DFS序中出现的顺序和在BFS中出现的顺序相同,所以BFS序中同一层的点出现的顺序应该和DFS序中出现的顺序相同。我们把这称为条件一。
    接下来,DFS序中相邻的两个点u,vv要么是u的某个祖先的儿子,要么是u的儿子,那么我们有depth(u)+1depth(v)。我们把这称为条件二。
    那么我们考虑对BFS序分层,实际上就是考虑在哪些间隙添加断点,那么期望层数就是期望断点数+1。首先在1后面是肯定要分层的,然后因为条件一的限制,如果两个在BFS序中相邻的点u,v中,u在DFS序中的出现位置比v的出现位置靠后,那么这两个点就不能被分在同一层中,它们中间必须有一个断点。再考虑条件二,我们可以把不等式写成depth(v)depth(u)1,也就是说,如果u在BFS序中在v之前,那么它们之间至多只能有一个断点,否则它们的深度差就会超过1。我们用已经确定必须要断的点来更新这种情况,即如果一个限制区间中已经有断点,那么限制区间中的其它点就不能断,这个可以用类似差分的标记方法解决。而对于没有断点的限制区间,可以证明这样的区间包含的间隙数目只可能为1(证明见下面的补证),那么这个点有12的概率是断点。根据期望的线性性,我们直接把每个间隙是断点的概率相加,就是期望断点数,再加上1就是期望层数,也就是树的期望高度了,时间复杂度为O(n)
    补一个小证明:不包含断点的限制区间包含的间隙数只能是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;
    }
  • 相关阅读:
    Leetcode#104. Maximum Depth of Binary Tree(二叉树的最大深度)
    Leetcode#70. Climbing Stairs(爬楼梯)
    Leetcode#88. Merge Sorted Array(合并两个有序数组)
    美团2019秋招后台开发编程题题解
    Leetcode#191. Number of 1 Bits(位1的个数)
    Leetcode#461. Hamming Distance(汉明距离)
    Leetcode#13. Roman to Integer(罗马数字转整数)
    Leetcode#521. Longest Uncommon Subsequence I(最长特殊序列 Ⅰ)
    Leetcode#557. Reverse Words in a String III(反转字符串中的单词 III)
    带你剖析WebGis的世界奥秘----瓦片式加载地图
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793378.html
Copyright © 2011-2022 走看看