感觉对树的理解更深了点
首先想到对BFS序列进行划分,那么方便起见,将BFS序列改为1~n的顺序排列,对应地改变DFS序列
对于同一种划分方案,有几棵满足DFS序的树呢?这相当于问子节点到父节点有几种连法。
在两种不同连法中,父1,父2,子 的相对顺序不同,所以只有一种符合DFS序。
也就是说:每种划分方案最多对应一棵树
接下来需要检验一种划分方案是否可行
每两次划分之间有一行深度相同的节点,所以从每行内部、行与行之间两个方面来考虑:
1. 设某一行为:l,l+1,…,r,只需满足DFS访问顺序是从左到右的,因此必须:pos[l]<pos[l+1]<…<pos[r] 其中 pos[i]:DFS序列中i出现的位置
2. 1) BFS序列中,1与2之间必须划分
2) 设改变后的DFS序列为a[1~n],depth(x)表示结点x在树中的深度
a[i]要么没孩子 -> depth(a[i])>=depth(a[i+1]),要么最先访问的孩子为a[i+1] -> depth(a[i])+1==depth(a[i+1])
所以对于任意i(1<=i<n), depth(a[i])+1>=depth(a[i+1])
有了判定方法,就可以统计方案数了
设x[i]为1表示i与i+1之间有划分,为0表示不划分,上述条件转化为:
① x[1]=1
② if(pos[i]>pos[i+1]) x[i]=1
③ if(a[i]<a[i+1]) x[a[i]]+x[a[i]+1]+…+x[a[i+1]-1] <=1 (若a[i]>a[i+1],显然成立; a[i]与a[i+1]间最多划分1次,否则深度相差2以上)
可以用②来"切分"③,使③中某些式子的变量值唯一确定
可以证明:③中那些还确定不了的式子一定只含一个未知数(a[j]==a[j+1]),这些x[i]既可为0又可为1,概率相等,给它们取值0.5就行了
算法复杂度为线性,记录③中那些单变量的不等式值是被否②+③确定时,使用了打标记的技巧而避免了使用线段树
ans=1+sigma(x[i])
代码和题解一样长。。。
#include<stdio.h>
#include<stdlib.h>
double x[200005]={0},s[200005]={0};
int t[200005]={0},a[200005]={0},pos[200005]={0},flag[200005]={0},sta[200005]={0};
int main()
{
double ans=1.0;
int n,i,j,p=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&j);
t[j]=i;//j在原DFS序的第i位上
}
for(i=1;i<=n;i++)
{
scanf("%d",&j);
a[t[j]]=i;
pos[i]=t[j];
}
x[1]=1.0;
for(i=1;i<n;i++)
{
if(pos[i]>pos[i+1]) x[i]=1.0;
if(x[i]==1.0)
{
flag[i]++;
flag[i+1]--;
}
s[i]=s[i-1]+x[i];
}
for(i=1;i<n;i++)
if(a[i]<a[i+1])
{
if(s[a[i+1]-1]-s[a[i]-1]>0)
{
flag[a[i]]++;
flag[a[i+1]]--;
}
else sta[++p]=a[i];
}
for(i=1;i<=n;i++)
flag[i]+=flag[i-1];
for(i=1;i<=p;i++)
if(flag[sta[i]]==0) x[sta[i]]=0.5;//flag[xi]==1意味着xi的值已经被确定
for(i=1;i<=n;i++)
ans+=x[i];
printf("%.3lf",ans);
return 0;
}