HDU5370 Tree Maker

来源:互联网 发布:工作室软件 编辑:程序博客网 时间:2024/06/05 21:50

题目链接

题目大意

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

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

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

1n500,x<500.

题解

再把问题抽象化一些,其实就是已知一棵二叉树某些子树的大小以及部分形态,求可能的方案数.
考虑一棵子树中没有子树大小限制的节点,我们可以计算出需要用多少个节点构造出多少棵可以为空的没有其他限制的二叉树,然后有子树大小限制的节点再去计算.
dp[i][j]表示用j个节点形成i棵可以为空的二叉树的方案数,这个可以在O(n3)时间内用Catalan数预处理出来.
然后对于每个case,只需遍历一遍形态已知的部分即可,复杂度是O(n)的.

写的时候被坑到了:操作时的x并不是这棵子树的最终大小,只是一次增加的节点个数.

代码

#include<cstdio>const int N=505,mod=1e9+7;int n,Cat[N],dp[N][N],que[N],L,R,ans,cnt_node,cnt_tree;struct Node{    int par,lson,rson,sz;    Node(int par=0,int lson=0,int rson=0,int sz=0):        par(par),lson(lson),rson(rson),sz(sz){}}tree[N];void init(){    Cat[0]=1;    for(int i=1;i<N;++i){        Cat[i]=0;        for(int j=0;j<i;++j)            Cat[i]=(Cat[i]+1ll*Cat[j]*Cat[i-1-j])%mod;    }    dp[0][0]=1;    for(int i=1;i<N;++i)        dp[0][i]=0;    for(int i=1;i<N;++i){        for(int j=0;j<N;++j){            dp[i][j]=0;            for(int k=0;k<=j;++k)                dp[i][j]=(dp[i][j]+1ll*dp[i-1][j-k]*Cat[k])%mod;        }    }}void dfs(int cur){    --cnt_node;    if(tree[cur].lson){        if(tree[tree[cur].lson].sz){            que[R++]=tree[cur].lson;        }        else dfs(tree[cur].lson);    }    else ++cnt_tree;    if(tree[cur].rson){        if(tree[tree[cur].rson].sz){            que[R++]=tree[cur].rson;        }        else dfs(tree[cur].rson);    }    else ++cnt_tree;}int solve(){    int allc=0,cur=0,sum=0,ope,x;    tree[allc++]=Node(0,0,0,0);    while(n--&&scanf("%d",&ope)){        switch(ope){            case 0:                cur=tree[cur].par;                break;            case 1:                if(!tree[cur].lson)                    tree[tree[cur].lson=allc++]=Node(cur,0,0,0);                cur=tree[cur].lson;                break;            case 2:                if(!tree[cur].rson)                    tree[tree[cur].rson=allc++]=Node(cur,0,0,0);                cur=tree[cur].rson;                break;            case 3:                scanf("%d",&x);                tree[tree[cur].lson=allc++]=Node(cur,0,0,x);                sum+=x;                break;            case 4:                scanf("%d",&x);                tree[tree[cur].rson=allc++]=Node(cur,0,0,x);                sum+=x;                break;        }       }    ans=1;    L=R=0;    if(tree[0].lson)que[R++]=tree[0].lson;    if(tree[0].rson)que[R++]=tree[0].rson;    while(L<R){        int elm=que[L++];        cnt_node=tree[elm].sz;        cnt_tree=0;        dfs(elm);        ans=1ll*ans*dp[cnt_tree][cnt_node]%mod;    }    return ans;}int main(){    int kase=0;    init();    while(~scanf("%d",&n)){        printf("Case #%d: %d\n",++kase,solve());    }    return 0;}/*    Jun.28.16    Tags:Catalan Number    Submissions:2    Memory(KB) 2440    Time(ms) 748    Length(Bytes) 1841*/
0 0
原创粉丝点击