Problem DescriptionTree 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?
InputThe 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.
OutputFor 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 Input23 34 323 31
Sample OutputCase #1: 25Case #2: 5HintBecause 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.
【题意】
有一个造二叉树的程序,初始时只有一个节点并且光标指向它,然后进行了5种操作之一:
- 光标指向当前节点的父亲节点.
- 光标指向当前节点的左儿子.
- 光标指向当前节点的右儿子.
- 随机造一棵包含x个节点的二叉树,把它作为当前节点的左子树.
- 随机造一棵包含x个节点的二叉树,把它作为当前节点的右子树.
给出这7取模.
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就好了。
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define LL long long 10 #define Mod 1000000007 11 #define Maxn 510 12 13 LL p[2*Maxn],c[Maxn]; 14 LL f[Maxn][Maxn]; 15 16 LL qpow(LL x,LL b) 17 { 18 LL ans=1; 19 while(b) 20 { 21 if(b&1) ans=(ans*x)%Mod; 22 x=(x*x)%Mod; 23 b>>=1; 24 } 25 return ans; 26 } 27 28 LL get_c(LL n) 29 { 30 LL k=qpow(p[n+1],Mod-2),ans=1; 31 ans=(p[2*n]*k)%Mod; 32 k=qpow(p[n],Mod-2); 33 ans=(ans*k)%Mod; 34 return ans; 35 } 36 37 void init() 38 { 39 p[0]=1; 40 for(LL i=1;i<=2*Maxn-10;i++) p[i]=(p[i-1]*i)%Mod; 41 for(LL i=0;i<=Maxn-10;i++) c[i]=get_c(i); 42 memset(f,0,sizeof(f)); 43 f[0][0]=1; 44 for(LL i=0;i<=Maxn-10;i++) f[1][i]=c[i]; 45 46 for(LL i=2;i<=Maxn-10;i++) 47 for(LL j=0;j<=Maxn-10;j++) 48 { 49 // f[i][j]=0; 50 for(LL k=0;k<=j;k++) 51 f[i][j]=(f[i][j]+f[i-1][j-k]*c[k])%Mod; 52 } 53 54 } 55 56 struct node 57 { 58 int x,lc,rc,f; 59 int sum,is; 60 bool al,ar; 61 }t[Maxn];int cnt; 62 63 struct hp 64 { 65 int x,id; 66 bool q; 67 }qy[Maxn];int ql; 68 69 void upd(int x) 70 { 71 t[x].is=0; t[x].sum=1; 72 t[x].sum+=t[x].al?0:t[t[x].lc].sum; 73 t[x].sum+=t[x].ar?0:t[t[x].rc].sum; 74 75 int y; 76 y=t[x].lc?t[t[x].lc].is:1; 77 if(t[x].al) y=0; 78 t[x].is+=y; 79 80 y=t[x].rc?t[t[x].rc].is:1; 81 if(t[x].ar) y=0; 82 t[x].is+=y; 83 } 84 85 int n; 86 bool ffind() 87 { 88 int now=1;cnt=1;ql=0; 89 t[1].lc=t[1].rc=0; 90 t[1].al=t[1].ar=0; 91 upd(1); 92 bool ok=1; 93 for(int i=1;i<=n;i++) 94 { 95 int opt; 96 scanf("%d",&opt);opt++; 97 if(opt==1) 98 { 99 if(now==1) ok=0; 100 now=t[now].f; 101 } 102 else if(opt==2) 103 { 104 if(!t[now].lc) 105 { 106 t[++cnt].f=now; 107 t[cnt].lc=t[cnt].rc=0; 108 t[cnt].al=t[cnt].ar=0; 109 upd(cnt); 110 t[now].lc=cnt; 111 upd(t[cnt].f); 112 } 113 now=t[now].lc; 114 } 115 else if(opt==3) 116 { 117 if(!t[now].rc) 118 { 119 t[++cnt].f=now; 120 t[cnt].lc=t[cnt].rc=0; 121 t[cnt].al=t[cnt].ar=0; 122 t[now].rc=cnt; 123 } 124 now=t[now].rc; 125 } 126 else if(opt==4) 127 { 128 if(t[now].al||t[now].lc) ok=0; 129 int x; 130 scanf("%d",&x); 131 qy[++ql].id=now;qy[ql].x=x;qy[ql].q=0; 132 t[now].al=1; 133 } 134 else 135 { 136 if(t[now].ar||t[now].rc) ok=0; 137 int x; 138 scanf("%d",&x); 139 qy[++ql].id=now;qy[ql].x=x;qy[ql].q=1; 140 t[now].ar=1; 141 } 142 } 143 return ok; 144 } 145 146 void dfs(int x) 147 { 148 if(t[x].lc) dfs(t[x].lc); 149 if(t[x].rc) dfs(t[x].rc); 150 upd(x); 151 } 152 153 LL get_ans() 154 { 155 LL ans=1; 156 for(int i=1;i<=ql;i++) 157 { 158 int now,y=qy[i].x; 159 if(qy[i].q==0) 160 { 161 if(t[qy[i].id].lc) now=t[t[qy[i].id].lc].is,y-=t[t[qy[i].id].lc].sum; 162 else now=1; 163 } 164 else 165 { 166 if(t[qy[i].id].rc) now=t[t[qy[i].id].rc].is,y-=t[t[qy[i].id].rc].sum; 167 else now=1; 168 } 169 if(y<0) return 0; 170 ans=(ans*f[now][y])%Mod; 171 } 172 return ans; 173 } 174 175 int main() 176 { 177 int T,kase=0; 178 init(); 179 while(scanf("%d",&n)!=EOF) 180 { 181 printf("Case #%d: ",++kase); 182 if(!ffind()) {printf("0\n");continue;} 183 dfs(1); 184 printf("%lld\n",get_ans()); 185 } 186 return 0; 187 }
2016-09-21 22:12:01