Tree Maker

Problem Description
Tree Lover loves trees crazily.

One day he invents an interesting game which is named Tree Maker.

In this game, all trees are binary trees.

Initially, there is a tree with only one vertex and a cursor on it. Tree Lover can control the cursor to apply 5 operations to build a tree, and their formats are following:

0 : Jump to the parent of the current vertex.

1 : Jump to the left child of the current vertex.

2 : Jump to the right child of the current vertex.

3 x : Generate a tree with x vertices arbitrarily and make it the left subtree of the current vertex.

4 x : Generate a tree with x vertices arbitrarily and make it the right subtree of the current vertex.

When applying an operation, the log system will log down a record of it.

Tree Lover played this game for a whole day yesterday. As a forgetful man, although Tree Lover knew the shape of the tree while playing, after a sleep he forgot it.

All he has now is the logs of operations.

Tree Lover wants to know: how many possible shapes of the tree can have yesterday according to the logs?

Can you answer this question?

Input
The input consists of multiple test cases.

For each test case:

The first line is an integer n (1 <= n <= 500), denoting the lines of logs.

Then follow n lines of logs. The formats of logs are as described above.

The integer x of operation 3 and 4 is positive.

In each case, the number of vertices of the tree will never exceed 500.

You can assume that the cursor will never jump to a non-existent vertex.

If the left child of a vertex exists, operation 3 will not be applied on this vertex, and operation 4 is similar.

Output
For each test case, ouput a single line “Case #x: y”, where x is the case number, starting from 1, and y is the answer to Tree Lover’s question.

Because the answer can be large, please output the answer mod 1000000007.

Sample Input
2
3 3
4 3
2
3 3
1
Sample Output
Case #1: 25
Case #2: 5
 
Hint

Because the tree is a binary tree, if left and right subtrees of a vertex are of different shapes, after swapping them, the new tree is considered different from the original one.

 
 
【题意】
  

  有一个造二叉树的程序,初始时只有一个节点并且光标指向它,然后进行了n次操作,每次操作属于以下5种操作之一:

  1. 光标指向当前节点的父亲节点.
  2. 光标指向当前节点的左儿子.
  3. 光标指向当前节点的右儿子.
  4. 随机造一棵包含x个节点的二叉树,把它作为当前节点的左子树.
  5. 随机造一棵包含x个节点的二叉树,把它作为当前节点的右子树.

  给出这n个操作,求在满足所有操作合法的前提下,共有多少种可能的二叉树被造出来,对109+7取模.

  1≤n≤500,∑x<500.

【分析】

  这是我做的最难的卡特兰数了,然而难在打的方面,真的要想清楚才行啊!!主要是dp部分,卡特兰数是求二叉树形态的。

  当只有操作1~3,我们可以准确知道这棵树,就是说我们可以准确知道这棵树的一部分,

  然后对于操作4~5,我们知道要插入i棵小树,一共j的点这样的信息。

  当要插入一颗大小为k的树时,方案数=卡特兰(k),

  然后dp求出用j个节点构成i棵可以为空的子树的方案数f[i][j],然后在树上走一遍然后统计即可。

  重点是求当前对于询问能插子树的位置以及未知点的个数。

  

  上图,箭头边x->y表示在x那里有一个插子树操作。(箭头指向位置可以为空,因为那个位置是未知的,插了一颗子树但是没有走到)。

  无向边表示没有进行插树操作但是走到了这个点,就是说这是给我们知道的对于未知子树的特别信息,是我们可以确定部分子树形态。

  操作每个点记录一个is[x],sum[x],sum[x]表示从x开始,不走箭头边能一共走到的点的个数。

  is[x]表示从x开始不走箭头边走到的点的插位个数(就是如果没有左孩子,就有1个插位位置,右孩子也一样)

  为什么要这样呢?如上图,1,2都有一个插左子树操作,那么3节点必定不是执行1插子树操作时产生的,2左子树上其他点也是如此,所以不能计入1操作的答案里。

  所以如果统计1插左子树操作时,询问一下2的sum[x]和is[x]即可,最后加上dp就好了。

代码如下:

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
#define LL long long
#define Mod 1000000007
#define Maxn 510 LL p[*Maxn],c[Maxn];
LL f[Maxn][Maxn]; LL qpow(LL x,LL b)
{
LL ans=;
while(b)
{
if(b&) ans=(ans*x)%Mod;
x=(x*x)%Mod;
b>>=;
}
return ans;
} LL get_c(LL n)
{
LL k=qpow(p[n+],Mod-),ans=;
ans=(p[*n]*k)%Mod;
k=qpow(p[n],Mod-);
ans=(ans*k)%Mod;
return ans;
} void init()
{
p[]=;
for(LL i=;i<=*Maxn-;i++) p[i]=(p[i-]*i)%Mod;
for(LL i=;i<=Maxn-;i++) c[i]=get_c(i);
memset(f,,sizeof(f));
f[][]=;
for(LL i=;i<=Maxn-;i++) f[][i]=c[i]; for(LL i=;i<=Maxn-;i++)
for(LL j=;j<=Maxn-;j++)
{
// f[i][j]=0;
for(LL k=;k<=j;k++)
f[i][j]=(f[i][j]+f[i-][j-k]*c[k])%Mod;
} } struct node
{
int x,lc,rc,f;
int sum,is;
bool al,ar;
}t[Maxn];int cnt; struct hp
{
int x,id;
bool q;
}qy[Maxn];int ql; void upd(int x)
{
t[x].is=; t[x].sum=;
t[x].sum+=t[x].al?:t[t[x].lc].sum;
t[x].sum+=t[x].ar?:t[t[x].rc].sum; int y;
y=t[x].lc?t[t[x].lc].is:;
if(t[x].al) y=;
t[x].is+=y; y=t[x].rc?t[t[x].rc].is:;
if(t[x].ar) y=;
t[x].is+=y;
} int n;
bool ffind()
{
int now=;cnt=;ql=;
t[].lc=t[].rc=;
t[].al=t[].ar=;
upd();
bool ok=;
for(int i=;i<=n;i++)
{
int opt;
scanf("%d",&opt);opt++;
if(opt==)
{
if(now==) ok=;
now=t[now].f;
}
else if(opt==)
{
if(!t[now].lc)
{
t[++cnt].f=now;
t[cnt].lc=t[cnt].rc=;
t[cnt].al=t[cnt].ar=;
upd(cnt);
t[now].lc=cnt;
upd(t[cnt].f);
}
now=t[now].lc;
}
else if(opt==)
{
if(!t[now].rc)
{
t[++cnt].f=now;
t[cnt].lc=t[cnt].rc=;
t[cnt].al=t[cnt].ar=;
t[now].rc=cnt;
}
now=t[now].rc;
}
else if(opt==)
{
if(t[now].al||t[now].lc) ok=;
int x;
scanf("%d",&x);
qy[++ql].id=now;qy[ql].x=x;qy[ql].q=;
t[now].al=;
}
else
{
if(t[now].ar||t[now].rc) ok=;
int x;
scanf("%d",&x);
qy[++ql].id=now;qy[ql].x=x;qy[ql].q=;
t[now].ar=;
}
}
return ok;
} void dfs(int x)
{
if(t[x].lc) dfs(t[x].lc);
if(t[x].rc) dfs(t[x].rc);
upd(x);
} LL get_ans()
{
LL ans=;
for(int i=;i<=ql;i++)
{
int now,y=qy[i].x;
if(qy[i].q==)
{
if(t[qy[i].id].lc) now=t[t[qy[i].id].lc].is,y-=t[t[qy[i].id].lc].sum;
else now=;
}
else
{
if(t[qy[i].id].rc) now=t[t[qy[i].id].rc].is,y-=t[t[qy[i].id].rc].sum;
else now=;
}
if(y<) return ;
ans=(ans*f[now][y])%Mod;
}
return ans;
} int main()
{
int T,kase=;
init();
while(scanf("%d",&n)!=EOF)
{
printf("Case #%d: ",++kase);
if(!ffind()) {printf("0\n");continue;}
dfs();
printf("%lld\n",get_ans());
}
return ;
}

[HDU 5370]

2016-09-21 22:12:01

【HDU 5370】 Tree Maker(卡特兰数+dp)的更多相关文章

  1. HDU 5370 Tree Maker

    一个显然的结论是,一棵n个结点的二叉树的形态数,是Catalan数第n项.

  2. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  3. HDU 5673 Robot【卡特兰数】

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5673 题意: 有一个机器人位于坐标原点上.每秒钟机器人都可以向右移到一个单位距离,或者在原地不动.如 ...

  4. HDU 5673 Robot ——(卡特兰数)

    先推荐一个关于卡特兰数的博客:http://blog.csdn.net/hackbuteer1/article/details/7450250. 卡特兰数一个应用就是,卡特兰数的第n项表示,现在进栈和 ...

  5. hdu5816 卡特兰数+dp

    题意:共n张无中生有,m张攻击牌.每张攻击牌攻击力已知,敌方有p点血.随机洗牌.游戏开始,己方抽取一张手牌,若是无中生有则可再抽两张牌.求能在第一回合内将敌方杀死的概率. n+m <= 20, ...

  6. HDU 4828 Grids(卡特兰数+乘法逆元)

    首先我按着我的理解说一下它为什么是卡特兰数,首先卡特兰数有一个很典型的应用就是求1~N个自然数出栈情况的种类数.而这里正好就对应了这种情况.我们要满足题目中给的条件,数字应该是从小到大放置的,1肯定在 ...

  7. hdu 1130How Many Trees?(卡特兰数)

    卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列. 以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名,其前几项为(从第零 ...

  8. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  9. HDU 5293 Tree chain problem 树形DP

    题意: 给出一棵\(n\)个节点的树和\(m\)条链,每条链有一个权值. 从中选出若干条链,两两不相交,并且使得权值之和最大. 分析: 题解 #include <cstdio> #incl ...

随机推荐

  1. Linux common resources

    Useful Linux Web reources list Linux die manual Linux Man Pages Archive Linux RPM find Linux RPM Sea ...

  2. samba服务器与远程登录ssh

    作者:相思羽  出处:http://www.cnblogs.com/xiang-siyu 欢迎转载,也请保留这段声明.谢谢! deepin安装与配置samba服务器 安装  apt-get insta ...

  3. C# winCE连接SQL数据库

    General network error.  Check your network documentation. 错误解决方法 1. public static string Sqlstr = &q ...

  4. c语言学习之基础知识点介绍(十三):枚举的介绍和使用

    一.枚举的介绍 /* 枚举:限制的待选项. 语法: enum 枚举名{ 选项1, 选项2, 选项3, ........ 选项n }; 注意:枚举中,选项之间用 , 隔开,最后一个不用加 , :并且枚举 ...

  5. 广告系统中weak-and算法原理及编码验证

    wand(weak and)算法基本思路 一般搜索的query比较短,但如果query比较长,如是一段文本,需要搜索相似的文本,这时候一般就需要wand算法,该算法在广告系统中有比较成熟的应 该,主要 ...

  6. static的用途

    1)限制变量的作用域:即在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变: 2)限制变量的存储域:<a>在模块内(但在函数体外),一个被声明为静态的变量,可以被模块内的所 ...

  7. 2015 Multi-University Training Contest 1 题解&&总结

    ---------- HDU 5288 OO’s Sequence 题意 给定一个数列(长度<$10^5$),求有多少区间[l,r],且区间内有多少数,满足区间内其它数不是他的约数. 数的范围$ ...

  8. AJAX 一些常用方法

    abort() 停止当前请求getAllResponseHeaders() 返回包含HTTP请求的所有响应头信息,其中响应头包括Content-Length,Date,URI等内容.getRespon ...

  9. CentOS安装+配置+远程

    这篇博客我之前写在了csdn,转了过来,这篇是自己认为写的比较有技术含量的文章^_^ 最近和CentOS打了交到,其中遇到了很多问题,于是看了一些博客,解决了一些问题,但是都不是特别全面,所以想来一篇 ...

  10. ajax GET和POST请求web api 的几种方式

    GET请求 1.无参数get请求 一般get请求有两种写法,一种是 $.get()   一种是$.ajax({type:"get"}), 我个人比较喜欢用后者. 下面例子主要是ge ...