题目描述

既然是萌萌哒$visit\text{_}world$的比赛,那必然会有一道计数题啦!
考虑一个$N$个节点的二叉树,它的节点被标上了$1\sim N$的编号。并且,编号为$i$的节点在二叉树的前序遍历中恰好是第$i$个出现。
我们定义$A_i$表示编号为$i$的点在二叉树的中序遍历中出现的位置。
现在,给出$M$个限制条件,第$i$个限制条件给出了$u_i,v_i$,表示$A_{u_i},A_{v_i}$你需要计算有多少种不同的带标号二叉树满足上述全部限制条件,答案对$10^9+7$取模。


输入格式

第一行一个整数$T(1\leqslant T\leqslant 5)$,表示数据组数。
每组数据第一行为两个整数$N,M$,意义如题目所述。
接下来$M$行,每行两个整数$u_i,v_i(1\leqslant u_i,v_i\leqslant N)$。描述一条限制。


输出格式

对每组数据,输出一行一个整数,表示答案。


样例

样例输入:

3
5 0
3 2
1 2
2 3
3 3
1 2
2 3
3 1

样例输出:

42
1
0


数据范围与提示

样例解释:

第一组数据,无任何限制时,$5$个点的二叉树形态个数为$42$。
第二组数据,唯一满足条件的二叉树的形态为$1-2-3$。($1$为根,$2,3$均为右儿子)。
第三组数据,限制条件产生矛盾。

数据范围:

对于全部的测试数据,保证$T\leqslant 5,N\leqslant 400,M\leqslant 10^3$
子任务$1$($20$分):$M=0$。
子任务$2$($15$分):$N\leqslant 10$。
子任务$3$($20$分):$N\leqslant 50,M\leqslant 1$。
子任务$4$($15$分):$N\leqslant 50$。
子任务$5$($30$分):无特殊限制。


题解

先来复习一下三种遍历序:

  $\alpha.$前(先)序遍历:根$\rightarrow$左$\rightarrow$右。

  $\beta,$中序遍历:左$\rightarrow$中$\rightarrow$右。

  $\gamma.$后序遍历:左$\rightarrow$右$\rightarrow$根。

为方便记忆,我们可以只记“根”在其中的位置就好了,先序遍历根在前,中序遍历根在中,后序遍历根在后,左在前右在后。

不妨从$M=0$的情况入手,你可能找规律发现是卡特兰数,简单证明一下:

  可以把放到左儿子认为是$+1$,放到右儿子认为是$-1$,所以是卡特兰数。

但是如果接着往下思考它就死了……

考虑换一个思路解决这个问题,考虑$DP$,设$dp[l][r]$表示点的编号区间$[l,r]$所能组成的不同形态的数的个数。

因为需要满足前序遍历序就是点的编号,所以$l$一定是根节点,且左右子树里点的编号也是分别连续的,所以我们可以得到转移方程:

$$dp[l][r]=\sum \limits_{i=l}^r dp[l+1][i]\times dp[i+1][r]$$

接着考虑带限制的情况,其实也很简单;不妨设两点$u$和$v$,且$u$的编号比$v$小。

如果存在限制要求在中序遍历中$v$在$u$之前,那么$v$一定要在$u$的左子树中;反之同理。

于是我们可以预处理出来一定在左子树中的编号最大的点(设为$L[i]$)和一定在右子树中的编号最小的点(设为$R[i]$),那么我们可以得到:

$$dp[l][r]=\sum \limits_{i=L[l]}^{R[l]}dp[l+1][i]\times dp[i+1][r])$$

于是这道题就解决了。

时间复杂度:$\Theta(n^3)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int N,M;
bool Map[401][401];
int L[401],R[401];
long long dp[401][401];
void pre_work()
{
memset(Map,0,sizeof(Map));
memset(dp,-1,sizeof(dp));
}
long long dfs(int l,int r)
{
if(l>r)return 1;
if(L[l]>r)return 0;
if(l==r)return 1;
if(dp[l][r]!=-1)return dp[l][r];
dp[l][r]=0;
for(int i=L[l];i<=min(R[l],r);i++)
dp[l][r]=(dp[l][r]+dfs(l+1,i)*dfs(i+1,r)%mod)%mod;
return dp[l][r];
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
pre_work();
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++)
{
int u,v;scanf("%d%d",&u,&v);
Map[u][v]=1;
}
for(int i=1;i<=N;i++)
{
L[i]=R[i]=i;
for(int j=i+1;j<=N;j++)if(Map[j][i])L[i]=j;
for(int j=i+1;j<=N;j++){if(Map[i][j])break;R[i]=j;}
}
printf("%lld\n",max(0LL,dfs(1,N)));
}
return 0;
}

rp++

[CSP-S模拟测试]:计数(DP+记忆化搜索)的更多相关文章

  1. 【bzoj5123】[Lydsy12月赛]线段树的匹配 树形dp+记忆化搜索

    题目描述 求一棵 $[1,n]$ 的线段树的最大匹配数目与方案数. $n\le 10^{18}$ 题解 树形dp+记忆化搜索 设 $f[l][r]$ 表示根节点为 $[l,r]$ 的线段树,匹配选择根 ...

  2. 【BZOJ】1415 [Noi2005]聪聪和可可 期望DP+记忆化搜索

    [题意]给定无向图,聪聪和可可各自位于一点,可可每单位时间随机向周围走一步或停留,聪聪每单位时间追两步(先走),问追到可可的期望时间.n<=1000. [算法]期望DP+记忆化搜索 [题解]首先 ...

  3. [题解](树形dp/记忆化搜索)luogu_P1040_加分二叉树

    树形dp/记忆化搜索 首先可以看出树形dp,因为第一个问题并不需要知道子树的样子, 然而第二个输出前序遍历,必须知道每个子树的根节点,需要在树形dp过程中记录,递归输出 那么如何求最大加分树——根据中 ...

  4. poj1664 dp记忆化搜索

    http://poj.org/problem?id=1664 Description 把M个相同的苹果放在N个相同的盘子里,同意有的盘子空着不放,问共同拥有多少种不同的分法?(用K表示)5.1.1和1 ...

  5. 状压DP+记忆化搜索 UVA 1252 Twenty Questions

    题目传送门 /* 题意:给出一系列的01字符串,问最少要问几个问题(列)能把它们区分出来 状态DP+记忆化搜索:dp[s1][s2]表示问题集合为s1.答案对错集合为s2时,还要问几次才能区分出来 若 ...

  6. ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2017)- K. Poor Ramzi -dp+记忆化搜索

    ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest (2017)- K. ...

  7. POJ 1088 DP=记忆化搜索

    话说DP=记忆化搜索这句话真不是虚的. 面对这道题目,题意很简单,但是DP的时候,方向分为四个,这个时候用递推就好难写了,你很难得到当前状态的前一个真实状态,这个时候记忆化搜索就派上用场啦! 通过对四 ...

  8. bzoj1833: [ZJOI2010]count 数字计数(数位DP+记忆化搜索)

    1833: [ZJOI2010]count 数字计数 题目:传送门 题解: 今天是躲不开各种恶心DP了??? %爆靖大佬啊!!! 据说是数位DP裸题...emmm学吧学吧 感觉记忆化搜索特别强: 定义 ...

  9. zoj 3644(dp + 记忆化搜索)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4834 思路:dp[i][j]表示当前节点在i,分数为j的路径条数,从 ...

  10. loj 1044(dp+记忆化搜索)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26764 思路:dp[pos]表示0-pos这段字符串最少分割的回文 ...

随机推荐

  1. Springboot2.x集成单节点Redis

    Springboot2.x集成单节点Redis 说明 在Springboot 1.x版本中,默认使用Jedis客户端来操作Redis,而在Springboot 2.x 版本中,默认使用Lettuce客 ...

  2. MySQL索引,备份和还原

    1.索引  1.索引是占硬盘空间 ,也是按页存放的 . 思考题:一个索引页,(数据页)  占用多少个字节  .SQL Server 8192个字节 2.索引:是一种有效组合数据的方式,为了快速查找指定 ...

  3. typescript是否可以直接编译执行?

    算是个有趣的小问题,由于必须依赖node.js,typescript理论上是不能不转成js直接运行的.

  4. C++中的新型类型转换

    1,C 语言中已经有类型之间的强制转换,C++ 做了改善: 2,C 方式的强制类型转换: 1,(Type) (Expression): 2,Type (Expression): 1,这种方式和上述方式 ...

  5. thinkPHP三级城市联动

    html+js: <!doctype html> <html lang="en"> <head> <meta charset=" ...

  6. HDU 1594 find the max

    数序问题. 题意是说 一个数列 a1,a2,--ai,--an;  x=i , y = ai:找两个点斜率绝对值.!最大. 第一次没找绝对值,--认真读题. .. x 每次加1 . 仅仅须要找 相邻的 ...

  7. Hbase0.96源码之HMaster(三)Hmaster主要循环

    1.Master初始化 1.1 if (!this.stopped) { finishInitialization(startupStatus, false); loop(); } 1.2 finis ...

  8. dajngo ORM查询中select_related的作用,博客主题的定制,从数据库中按照年月筛选时间

    1.dajngo ORM查询中select_related的作用 select_related()方法一次性的把数据库关联的对象都查询出来放入对象中,再次查询时就不需要再连接数据库,节省了后面查询数据 ...

  9. 小程序中页面兼容h5标签的解析

    有时候当小程序向后台拿数据是一篇html标签的文章时,把它放进小程序会发现很多标签就不兼容,如果要一个个改又很麻烦,有没有方法可以很快地兼容html标签呢? 有个工具可以做到:wxParse 下载了它 ...

  10. python学习笔记(2):科学计算及数据可视化入门

    一.NumPy 1.NumPy:Numberical Python 2.高性能科学计算和数据分析的基础包 3.ndarray,多维数组(矩阵),具有矢量运算的能力,快速.节省空间 (1)ndarray ...