NOI2013 树的计数
NOI2013 树的计数
给定一个dfs序和bfs序,求解符合这两个条件的所有树的平均树高。
思路
如果我们能够给bfs序中每一段区间分层,然后再去对应dfs序,不难发现可以唯一确定一棵树,即在dfs的过程中,前后两个节点的关系可以按照层数来判断,分为儿子或者是某一层祖先的另外一个儿子。
而给bfs序分层的时候我们需要满足一些限制:
- bfs序中同一层在dfs中访问顺序必须严格按照bfs的访问顺序来。
- dfs中每一次只能往下走一层或者是往上走若干层或者还停留在这一层。
- 1号点必须要分层。
接下来考虑怎么求解树高,bfs按照限制分完层之后会有一些断点,我们可以求出在满足限制的情况下每一个点成为端点的期望是多少,最后根据期望的线性性直接相加就可以得到最后的答案。
考虑如何去满足这些限制。
从1号限制的逆否命题可以退出,如果相邻的两个点在dfs中没有按照编号的顺序来,那么它们一定不在同一层,即pos[i]>pos[i+1],那么可以肯定i一定是断点,不难发现满足了这个限制就满足了1号限制。
-
在dfs序中相邻的两个点d[i],d[i+1],如果d[i+1] < d[i],那么i+1一定是i某一个祖先的另一个儿子,它们之间的断点个数是可以任意的。
-
如果d[i+1]>d[i]+1,它们一定不是兄弟的关系,也就是这两个点只能做父子,并且它们之间的断点个数一定为1,也就是我们可以标记这中间所有的点,它们都是已经确定的。
-
如果d[i+1]=d[i]+1,它们既可以做父子又可以做兄弟,它们之间的关系也是任意的。
但是上面1.3情况的任意取值都受2情况的影响,我们标记所有2情况影响的点,然后对于剩下的没有标记的点就可以任意取值,期望为0.5。
最后的答案就是确定为1的点加上期望为0.5的点。
// luogu-judger-enable-o2
/*=======================================
* Author : ylsoi
* Time : 2019.6.18
* Problem : luogu1232
* E-mail : ylsoi@foxmail.com
* ====================================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;
using namespace std;
void File(){
freopen("luogu1232.in","r",stdin);
freopen("luogu1232.out","w",stdout);
}
template<typename T>void read(T &_){
_=0; T f=1; char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
_*=f;
}
string proc(){
ifstream f("/proc/self/status");
return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
}
const int maxn=2e5+10;
int n,b[maxn],d[maxn],pb[maxn],pd[maxn],vis[maxn];
double ans;
int main(){
//File();
read(n);
REP(i,1,n)read(d[i]);
REP(i,1,n)read(b[i]),pb[b[i]]=i;
REP(i,1,n)d[i]=pb[d[i]],pd[d[i]]=i;
REP(i,2,n-1){
if(pd[i]>pd[i+1])ans+=1,++vis[i],--vis[i+1];
if(d[i]+1<d[i+1])++vis[d[i]],--vis[d[i+1]];
}
REP(i,3,n)vis[i]+=vis[i-1];
REP(i,2,n-1)if(!vis[i])ans+=0.5;
printf("%.3lf\n",ans+2);
return 0;
}