[NOI2013]树的计数
给定树的dfs序和bfs序,显然是通过它们之间的互相约束以得出答案。
为了方便,对编号做修改(不影响答案)。
dfs序改为:bfs序为1,2,...,n时的dfs序(设为d[i])
bfs序改为:dfs序为1,2,...,n时的bfs序(设为b[i])
树高h如何表示?假设将bfs序分成i段,h=i,每段内的所有点都在同一层
而任意点k后,分段/不分段,对平均树高H的贡献为1/0
每个k有3种情况:
①只能分段,H+=1
②分不分都行,H+=0.5
③不能分,H+=0
对于②、③,我们用一个差分数组s[i]表示状态。
累计s[i]的前缀和ts,ts=0为②,ts>0为③
至于①,我们可以直接处理掉,下面会讲
注意,对于根节点1,它只能分成单独的一段(一种①)
有个问题,bfs序并不能能随意分段,要受到dfs序的限制(用s[i]表示)
观察发现,假设我们将bfs序中的[l,r]分成一段,必须满足b[l]<b[l+1]<...<b[r]
因为在同一层内,dfs扫点一定是从左到右
所以dfs序一定是从左到右递增的(dfs序已经为1...n)。
于是得出一个约束条件:b[i]>b[i+1]时,i和i+1显然不能分到同一层内,必须断开。(另一种①)
接下来考虑bfs序对dfs序的限制
还是考虑dfs序上两个相邻的点i,i+1
发现它们之间有3种关系(红点为i,蓝点为i+1)
1.i和i+1是兄弟(i没有儿子)
2.i+1是i的祖先的某个儿子(i没有儿子)
3.i+1是i的儿子
发现第3种情况有点东西:
bfs序上d[i]~d[i+1]之间最多只能切一次段,因为i和i+1之间只差一层
而且切这一段的贡献已经在①中被算过了
于是d[i]~d[i+1]就不能再贡献啥了,也就是总贡献=0,H+=0
然鹅怎么把第1,2种情况筛掉呢
发现对于第1种,d[i]>d[i+1]
对于第2种,d[i]+1=d[i+1]
(或者第3种的一层只有i,下一层只有i+1。把它筛掉没有影响)
d[i]+1<d[i+1]时,只能是第3种情况
于是我们又得出了一个约束条件:d[i]+1<d[i+1]时,bfs序中的[d[i],d[i+1]]不会再产生贡献(③)
剩下不被约束的点都属于②,H+=0.5,表示取/不取产生贡献的平均值(0+1)/2
再注意一些小细节(见code)于是就可以搞定这个思维题辣
#include<iostream> #include<cstdio> #define rint register int using namespace std; #define N 200005 int read(){ char c=getchar();int x=0; while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar(); return x; } int n,s[N],b[N],d[N],a[N],c[N]; double ans; int main(){ n=read(); ans=2; ++s[1];--s[2];//ans=2:根节点算1层+最下面的1层=2层 for(rint i=1;i<=n;++i) a[d[i]=read()]=i; for(rint i=1;i<=n;++i) c[b[i]=read()]=i; for(rint i=1;i<=n;++i) d[i]=c[d[i]],b[i]=a[b[i]]; for(rint i=1;i<n;++i) if(b[i]>b[i+1]) ++s[i],--s[i+1],++ans;//ans没有算到最下面的一层,先加上去 for(rint i=1;i<n;++i) if(d[i]+1<d[i+1]) ++s[d[i]],--s[d[i+1]]; for(rint i=1,w=0;i<n;++i) w+=s[i],ans+=w?0:0.5;//第n个点后面都是空的给它分段有什么意义吗 // printf("%.3f\n%.3f\n%.3f",ans-0.001,ans,ans+0.001); // bzoj需要输出以上ans-0.001,ans,ans+0.001(大雾) printf("%.3f",ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了