[HEOI2013] SAO
This question is a good question counts investigated swap the order of summation and then prefixes and optimization , design difficulties in the state, more study thinking.
A topic intended: to give you a number, there is a tree edge to edge, find the topological order.
The number of DAG topology is seeking a NP problem, but here is guaranteed to be a tree, so we can use a tree DP to solve.
The design condition, the light set node numbers \ (U \) is not enough, but also need to design a one-dimensional \ (I \) represents the junction \ (U \) in order to \ (U \) topological subtree rooted in sequences in the \ (i \) position, so we can write the transfer equation.
For \ (U \ rightarrow V \)
\ [F. '[U] [K] = \ Sigma_ {V \ in Son} F. [U] [I] \ Times F. [V] [J] \ Times \ tbinom {K -1} {i-1} \
times \ tbinom {size_u + size_v-k} {size_u-i}, i \ leq k \ leq i + j-1 \] to \ (U \ LeftArrow V \)
\ [F. '[u] [k] = \ Sigma_ {v \ in son} F [u] [i] \ times F [v] [j] \ times \ tbinom {k-1} {i-1} \ times \ tbinom {size_u + size_v-k} {
size_u-i}, i + j \ leq k \ leq size_v + i \] objectives:
\ [\ Sigma_. 1 = {I} ^ {N} F. [. 1] [I] \]
(all nodes of the standard automatic + 1)
found definitely not triple loop, the exchange \ (J \) and \ (K \) sequence found \ (F [v] [j ] \) can be processed and a prefix, a one-dimensional cut off.
In fact do so by the overall complexity of the \ (\ text {O} ( N ^ 3) \) reduced \ (\ text {O} (N ^ 2) \) . (Careful study of the following code is found in practice that the processing times of the number of points)
look at the details code.
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define INF (1 << 30)
#define chkmax(a, b) a = max(a, b)
#define chkmin(a, b) a = min(a, b);
inline int read() {
int w = 0, f = 1; char c;
while (!isdigit(c = getchar())) f = c == '-' ? -1 : f;
while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ 48), c = getchar();
return w * f;
}
inline int read_ch() {
char c;
while (c = getchar(), c != '>' && c != '<');
return c == '<';
}
const int maxn = 1000 + 5;
const int MOD = 1e9 + 7;
struct Edge {
int v, w, pre;
} e[maxn << 1];
int m, G[maxn];
void clear() {
m = 0;
memset(G, -1, sizeof(G));
}
void add(int u, int v, int w) {
e[m++] = (Edge){v, w, G[u]};
G[u] = m-1;
}
int T, N;
int f[maxn][maxn], g[maxn], C[maxn][maxn];
void inc(int &a, int b) {
a += b;
if (a >= MOD) a -= MOD;
}
int dec(int a) {
if (a < 0) a += MOD;
return a;
}
void init() {
C[0][0] = 1;
for (register int i = 1; i <= 1000; i++) {
C[i][0] = 1;
for (register int j = 1; j <= i; j++)
C[i][j] = (C[i-1][j] + C[i-1][j-1]) % MOD;
}
}
int size[maxn];
void dfs(int u, int fa) {
size[u] = 1;
f[u][1] = 1;
for (register int i = G[u]; ~i; i = e[i].pre) { \\ 这里实际上相当于u<->v之间的拓扑序合并起来
int v = e[i].v;
if (v == fa) continue;
dfs(v, u);
memcpy(g, f[u], sizeof(g));
memset(f[u], 0, sizeof(f[u]));
if (e[i].w) {
for (register int i = 1; i <= size[u]; i++)
for (register int k = i; k <= i+size[v]-1; k++)
inc(f[u][k], (ll)g[i] * dec(f[v][size[v]]-f[v][k-i]) % MOD * C[k-1][i-1] % MOD * C[size[u]+size[v]-k][size[u]-i] % MOD);
} else {
for (register int i = 1; i <= size[u]; i++)
for (register int k = i+1; k <= size[v] + i; k++)
inc(f[u][k], (ll)g[i] * dec(f[v][k-i]) % MOD * C[k-1][i-1] % MOD * C[size[u]+size[v]-k][size[u]-i] % MOD);
}
size[u] += size[v];
}
for (register int i = 1; i <= size[u]; i++) inc(f[u][i], f[u][i-1]);
}
int main() {
init();
T = read();
while (T--) {
N = read();
clear();
for (register int i = 1; i < N; i++) {
int u = read()+1, opt = read_ch(), v = read()+1;
add(u, v, opt); add(v, u, !opt);
}
dfs(1, 1);
printf("%d\n", f[1][N]);
}
return 0;
}