本题的本质是求排列的数目。要求在排列里面,任何一个元素不能早于它的祖先节点。我们来考虑这样一个简单的情况
A
/ \
B D
| |
C E
对于A这棵子树而言,它的合法的permuation有6种,一定是A####的形式。在这四个####的全排列里面,我们要求B一定在C前面,D一定在E前面。但是B、C与D、E之间的关系是任意的。所以我们可以考虑将B、C抽象为X,将D、E抽象为Y,那么X和Y之间是没有任何约束关系的,所以我们可以将X和Y任意全排列。于是我们第一步考察两个X和两个Y的unique的全排列的数目是多少?答案是6个:
XXYY
XYXY
XYYX
YYXX
YXYX
YXXY
这个排列数是怎么求出来的呢?我们先考虑一个总的全排列数目4!=24。但是因为X元素位置上的子排列我们不细分,即..x1..x2..
与..x2..x1..
,在我们眼中都是..x..x..
,所以我们要除以x元素内部的排列数。同理,也要除以y元素内部的排列数。所以“两个X和两个Y的unique的全排列的数目”就是4!/(2!*2!)=6
.
上面的排列数忽略了X元素内部的任何不同排列,以及Y元素内部的任何不同排列。那么X元素内部有多少种不同的排列呢?这其实就是以B为根的子树的排列数(在这个例子中是1). 假设以B为根的子树的排列数是a,以D为根的子树的排列数是b,那么以A为根的子树的排列数就是在6的基础上,再乘以a*b
。
综上我们令dp[node]表示以node为节点的子树的排列数,num[node]表示以node为节点的子树的节点数目,那么就有递推公式:
dp[node] = num[node] ! / (num[child1]! * num[child2]! * ... * num[childk]!) * dp[child1] * dp[child2] * ... * dp[childk]
注意到上述的式子中含有除法,对大数取模的过程遇到除法需要用到逆元运算,即
(a / b) % M = a * inv(b, M)
关于逆元计算的模板见这里