*******************欢迎探讨
未补:A:未补原因:赛时已过:无算法
未补:B:未补原因:赛时已过:无算法
未补:C:未补原因:赛时已过:无算法
未补:D:未补原因:赛时已过:无算法
未补:E:未补原因:赛时已过:模拟
补题:F:树形dp
小吐槽:树形dp,赛时没时间写(写了也不一定会),因为我脑残到t2一直没过
题目大意:有很多家公司,每家公司有严格的上下级关系,可以看成一棵树,每个子树上面的节点不能在他的根的前面,但是A子树里面的节点可以在B子树的根的前面,这些节点要排成一排求方案数
解题思路:考虑最深的节点自然是1,向上的节点其排队的方案数为当前的子树的大小选出一个分支子树上的所有元素先选最后的倒着选所以子树每次加上当前分支子树,再选当前分支子树,最后再乘以分支子树上的方案数,多家公司和上面的选择方法相同,先选最后的公司,添加新的公司给新的公司选位置,最后加的是最先选的
核心代码:
int n, m;
int e[N], ne[N], h[N], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int f[N], sz[N];
int in[N], inv[N];
int qmi(int a, int k) {
int res = 1;
while(k) {
if(k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
void init() {
in[0] = inv[0] = 1;
for(int i = 1; i < N; i ++) in[i] = in[i - 1] * i % mod;
inv[N - 1] = qmi(in[N - 1], mod - 2);
for(int i = N - 2; i >= 1; i --)
inv[i] = inv[i + 1] * (i + 1) % mod;
}
int C(int a, int b) {
return in[a] * inv[b] % mod * inv[a - b] % mod;
}
void dfs(int u, int ff) {
sz[u] = 1, f[u] = 1;
int w = 0;
for(int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if(j == ff) continue;
dfs(j, u);
sz[u] += sz[j];
w += sz[j];
f[u] = (f[u] * f[j] % mod) * C(w, sz[j]) % mod;
}
}
void solve() {
rd(m); init();
int ans = 1;
int w = 0;
while (m--) {
rd(n); w += n;
for(int i = 1; i <= n; i ++) f[i] = 1, h[i] = -1;
for(int i = 2; i <= n; i ++) {
int x; rd(x);
add(i, x), add(x, i);
}
dfs(1, 0);
int res = f[1];
ans = ans * (res * C(w, n) % mod) % mod;
}
pf(ans, 1);
}