题目描述

既然是萌萌哒$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. 掌握这些 Redis 技巧,百亿数据量不在话下!

    一.Redis封装架构讲解 实际上NewLife.Redis是一个完整的Redis协议功能的实现,但是Redis的核心功能并没有在这里面,而是在NewLife.Core里面. 这里可以打开看一下,Ne ...

  2. 使用Postwoman

    postman的脱单产品postwoman 一.安装 1.使用git进行安装: git clone https://github.com/liyasthomas/postwoman cd postwo ...

  3. thinkphp整合Ueditor编辑器

    编辑器下载地址:http://ueditor.baidu.com/website/download.html#ueditor 放在项目Public或者入口同级目录均可. 前台代码 <div cl ...

  4. 3.golang 的注释

    package main import ( "fmt" "math" ) func main() { fmt.Println(pi(5000)) } // pi ...

  5. 【已解决】Error running 'xxx项目' Command line is too long(idea版)

    [错误] Error running 'xxx项目': Command line is too long. Shorten command line for xxx or also for Sprin ...

  6. django部署到linux上不显示.svg图标处理方法

    在setting文件的最开始添加如下内容: import mimetypes mimetypes.add_type("image/svg+xml", ".svg" ...

  7. oracle数据库中的游标

    oracle中的游标,游标的概念与作用,游标的分类,游标的使用. 一,游标的概念与作用 摘自百度百科:游标(Cursor)是处理数据的一种方法,为了查看或者处理结果集中的数据,游标提供了在结果集中一次 ...

  8. MySQL索引优化(索引两表优化案例)

    建表SQL CREATE TABLE IF NOT EXISTS `class` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `card` INT ...

  9. 2018-8-10-VisualStudio-修改配色

    title author date CreateTime categories VisualStudio 修改配色 lindexi 2018-08-10 19:16:52 +0800 2018-2-1 ...

  10. Apache 的 bin 目录文件详解

    [root@Apache bin]# tree ├── ab    #Apache 性能测试工具 ├── apachectl    #Apache 启动命令,它是一个脚本 ├── apr-1-conf ...