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;
    }
  • 相关阅读:
    爬虫-selenium模块
    动画《区块链100问》第4集:第一个比特币诞生啦!
    动画《区块链100问》第5集:谁是中本聪?
    动画《区块链100问》第6集:密码朋克是什么?
    动画《区块链100问》第7集:比特币是怎么发行的?
    动画《区块链100问》第8集:披萨居然卖到3亿元?
    动画《区块链100问》第9集:中本聪的继任者是谁?
    动画《区块链100问》第10集:早期比特币还能白送!
    《区块链100问》第11集:比特币为什么还没挖完?
    《区块链100问》第12集:比特币如何实现总量恒定?
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793378.html
Copyright © 2011-2022 走看看