思路:
很显然,公司关系构成了一棵树,该题实质求子树的拓扑序的方案数。考虑树形dp。
设
f
[
u
]
f[u]
f[u]表示以
u
u
u为子树的拓扑序的数量。
转移:
f
[
u
]
=
(
s
z
[
u
]
−
1
)
!
∗
∑
y
s
o
n
f
[
j
]
s
z
[
j
]
!
f[u]=(sz[u]-1)! *\sum_{y}^{son}\frac{f[j]}{sz[j]!}
f[u]=(sz[u]−1)!∗∑ysonsz[j]!f[j]。
对于
n
n
n个公司,我们建一个虚点作为它们的根。
code:
template <typename T> void inline read(T& x) {
T f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
template <typename T> void inline pr(T x) {
if (x < 0) { putchar('-'); pr(-x); return; }
if (x >= 10) pr(x / 10);
putchar((x % 10) + '0');
}
template <typename T> T inline qpow(T a, T b, T mod) {
T ans = 1;
for (; b; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod;
return ans;
}
//----------------------------------------------------------------------------------------//
template<int m>
struct modint{
unsigned int x;
constexpr modint() noexcept : x(){}
template<typename T>
constexpr modint(T x_) noexcept : x((x_ %= m) < 0 ? x_ + m : x_) {}
constexpr unsigned int val() const noexcept { return x; }
constexpr modint &operator ++() noexcept { if(++x == m) x = 0; return *this; }
constexpr modint &operator --() noexcept { if(x == 0) x = m; --x; return *this; }
constexpr modint operator ++(int) noexcept { modint res = *this; ++ *this; return res; }
constexpr modint operator --(int) noexcept{ modint res = *this;-- *this; return res; }
constexpr modint &operator += (const modint &a) noexcept{ x += a.x; if(x >= m) x -= m; return *this; }
constexpr modint &operator -= (const modint &a) noexcept{ if(x < a.x) x += m; x -= a.x; return *this; }
constexpr modint &operator *= (const modint &a) noexcept{ x = (unsigned long long)x * a.x % m; return *this;}
constexpr modint &operator /= (const modint &a) noexcept{ return *this *= a.inv(); }
constexpr modint operator +() const noexcept { return *this; }
constexpr modint operator -() const noexcept { return modint()-*this; }
constexpr modint pow(long long n) const noexcept {
if(n < 0) return pow(-n).inv();
modint x = *this, r = 1;
for(; n; x *= x,n >>= 1) if(n & 1) r *= x;
return r;
}
constexpr modint inv() const noexcept {
int s = x, t = m, x = 1, u = 0;
while(t) {
int k = s / t; s -= k * t;
swap(s,t); x -= k * u;
swap(x,u);
}
return modint(x);
}
friend constexpr modint operator + (const modint &a, const modint &b) { return modint(a) += b; }
friend constexpr modint operator - (const modint &a, const modint &b) { return modint(a) -= b; }
friend constexpr modint operator * (const modint &a, const modint &b) { return modint(a) *= b; }
friend constexpr modint operator / (const modint &a, const modint &b) { return modint(a) /= b; }
friend constexpr bool operator == (const modint &a, const modint &b) { return a.x == b.x; }
friend constexpr bool operator != (const modint &a, const modint &b) { return a.x != b.x; }
friend ostream &operator << (ostream &os,const modint &a){ return os << a.x;}
friend istream &operator >> (istream &is,modint &a){ long long v; is >> v; a = modint(v); return is; }
};
using mint = modint<1000000007>;
// using mint = modint<998244353>;
namespace Combine{
const int Combine_max = 3e5 + 50;
mint fac[Combine_max];
void init() { fac[0] = 1; for (int i = 1; i < Combine_max; ++ i) fac[i] = fac[i - 1] * i; }
mint A(int n, int m) { return fac[n] / fac[n - m]; }
mint C(int n, int m) { return fac[n] / (fac[n - m] * fac[m]); }
mint ksm(mint x, int exp){
mint res = 1;
for (; exp; x *= x, exp >>= 1) if (exp & 1) res *= x;
return res;
}
}
using namespace Combine;
const int N = 2e5 + 10, M = N * 2, mod = 1e9 + 7;
int h[N], e[M], ne[M], idx;
int n, sz[N];
mint f[N];
void add(int a, int b) {
e[idx] = b; ne[idx] = h[a]; h[a] = idx++;
}
void dfs(int u, int fa) {
sz[u] = 1;
f[u] = 1;
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == fa) continue;
dfs(j, u);
sz[u] += sz[j];
// mint x = sz[j];
f[u] = f[u] * f[j] * ksm(fac[sz[j]], mod - 2);
}
f[u] *= fac[sz[u] - 1];
}
signed main() {
#ifdef JANGYI
freopen("input.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
init();
read(n);
mint ans = 1;
int cnt = 0;
rep(i, 1, n) {
idx = 0;
int m; read(m);
cnt += m;
rep(i, 0, m) h[i] = -1, sz[i] = 0, f[i] = 0;
rep(i, 2, m) {
int x; read(x);
add(x, i);
}
dfs(1, 0);
// D(f[1])
ans *= f[1] * ksm(fac[m], mod - 2);
// cout << ksm(m, mod - 2);
}
// cout << fac[cnt] << '\n';
ans *= fac[cnt];
cout << ans << '\n';
return 0;
}