BZOJ3244:[Noi2013]树的计数 (树的遍历)
来源:互联网 发布:淘宝哪里可以回收手机 编辑:程序博客网 时间:2024/06/06 00:18
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3244
题目分析:一道超级难想的题,我YY了好几天都不会做,最后只好%一波网上大神的题解QAQ。
由于编号没有什么用,我们将BFS序强行设为1~n,并对应地改DFS序。现在我们考虑对着BFS序分层,每一层对应BFS序上的一个区间。然后要分析出一下三个结论:
①:1号点单独分一层。
②:如果i号点在DFS序中的位置比i+1号点要后,那么i号点与i+1号点之间一定隔了一层。
③:考虑DFS序上相邻的两个点(a,b),很明显b的深度不会超过a的深度+1。所以如果
那么如何分层才能满足上述条件呢?我们先将①,②条件处理完,构造一个前缀和数组。然后逐一处理③条件,如果a与b之间已经有某个地方分了层,其它地方就一定不能分层。这可以通过
那么最终的情况就是:某些相邻点对(i,i+1)之间一定要分层,某些一定不能,还有一些不确定。对于不确定的点对,它们之间分不分层,对其它点没有影响,所以它们对答案的贡献是0.5。
那么其实还有一个疑问:③条件其实是限制了某个区间的分层数小于等于1,可如果最后这个区间的所有相邻点对是否分层都是不确定的,那么每个点对对答案的贡献就不可以是0.5。但事实上这种情况是不会发生的。因为对于DFS序上相邻的点对(a,b),且
注意在B站上提交,要输出3行答案,分别是ans-0.001,ans,ans+0.001。
下面扯一下我一开始拿到这题的一个
首先还是重编号,然后考虑分治。令Solve(L,R)返回一个double数组a,其中a[i]表示DFS序上L~R的一段组成若干棵树,其中最高的深度为i的概率。则很明显令ans=Solve(2,n),
再考虑一下怎么求Solve(L,R)。令x=DFS序的第L位,先取出L~R中从x开始的极长连续上升子串,设其长度为len。那么这一段组成高度为i的树,概率为
然而事实上这样是有问题的,因为划分的子区间之间会相互影响。举个例子:
DFS[]={1,2,5,3,6,7,4,8,9,10}
划分成子区间{6,7}和{8,9,10}的时候如果前者的深度为2,后者的深度为1,就会和BFS序冲突。
尽管如此,这个方法还是拿了30分。或许是数据太弱了吧……
CODE:
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=200100;int bfsx[maxn];int dfsx[maxn];int val[maxn];int id[maxn];int sum[maxn];int cnt[maxn];int n;int main(){ freopen("3244.in","r",stdin); freopen("std.out","w",stdout); scanf("%d",&n); for (int i=1; i<=n; i++) scanf("%d",&dfsx[i]); for (int i=1; i<=n; i++) scanf("%d",&bfsx[i]); for (int i=1; i<=n; i++) val[ bfsx[i] ]=i; for (int i=1; i<=n; i++) dfsx[i]=val[ dfsx[i] ],id[ dfsx[i] ]=i; for (int i=1; i<n; i++) if (id[i]>id[i+1]) sum[i]=1; sum[1]=1; for (int i=2; i<n; i++) sum[i]+=sum[i-1]; for (int i=1; i<n; i++) { int a=dfsx[i],b=dfsx[i+1]; if (a<b) { b--; if (sum[b]-sum[a-1]>=1) cnt[a]++,cnt[b+1]--; } } for (int i=n-1; i>=2; i--) sum[i]-=sum[i-1]; int now=0; for (int i=1; i<n; i++) { now+=cnt[i]; if ( !now && !sum[i] ) sum[i]=2; } int temp=2; for (int i=1; i<=n; i++) if (sum[i]==1) temp+=2; else if (sum[i]==2) temp++; double ans=(double)temp/2.0; printf("%.3lf\n%.3lf\n%.3lf\n",ans-0.001,ans,ans+0.001); return 0;}
- BZOJ3244:[Noi2013]树的计数 (树的遍历)
- BZOJ3244[NOI2013树的计数]
- BZOJ3244: [Noi2013]树的计数
- bzoj3244: [Noi2013]树的计数
- 【BZOJ3244】【NOI2013】树的计数
- bzoj3244 NOI2013树的计数 神奇脑洞题+线段树
- 【NOI2013】树的计数
- bzoj 3244: Noi2013树的计数
- 【BFS和DFS的性质】[NOI2013]树的计数
- bzoj 3244: [Noi2013]树的计数 递推
- [NOI2013]树的计数(树的DFS,BFS序性质)
- JZOJ3332【NOI2013模拟】棋盘游戏 特判边界的计数问题(BZOJ 4705)
- 基于计数栈的非递归二叉树遍历算法
- NOI2013快餐店【图上找环+线段树】
- 【树DP+基环树】[NOI2013]快餐店
- 【BZOJ1211】树的计数(HNOI2004)-Prufer序列+组合计数
- 生成树的计数
- 二叉树的计数
- LVS调度器之间的高可用(脚本)
- UART配置调试指南
- 通信网络编程第三次作业
- Linux进程控制编程
- Java+MySQL实现附近功能
- BZOJ3244:[Noi2013]树的计数 (树的遍历)
- samba
- java实战项目视频学习
- Java问答题(1)
- 第十七章经典抽象数据结构二:树(数组实现)
- 【Scikit-Learn 中文文档】大规模计算的策略: 更大量的数据
- ROS 控制机器人走正方形
- Dijkstra算法 最短路径
- python学习—Day38—memcache安装以及群集操作