两条路径的交点数量只和起点数量有关。容易发现是终点排列的逆序对数的奇偶性。求一个 \(f_{i, j}\) 表示从第 \(1\) 层的第 \(i\) 个点到第 \(k\) 层的第 \(j\) 个点的路径数量,对这个矩阵求行列式即可。
对于相交的路径数不用考虑,因为总存在和它对应的一条路径,满足两条路径的终点排列的逆序对数一奇一偶(LGV 引理的本质)。
code
// Problem: P7736 [NOI2021] 路径交点
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7736
// Memory Limit: 1 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 210;
const ll mod = 998244353;
inline ll qpow(ll b, ll p) {
ll res = 1;
while (p) {
if (p & 1) {
res = res * b % mod;
}
b = b * b % mod;
p >>= 1;
}
return res;
}
ll n, a[maxn], b[maxn];
struct mat {
ll n, m, a[maxn][maxn];
mat(ll _n = 0, ll _m = 0) {
n = _n;
m = _m;
mems(a, 0);
}
} A;
inline mat operator * (const mat &a, const mat &b) {
mat res(a.n, b.m);
for (int k = 1; k <= a.m; ++k) {
for (int i = 1; i <= a.n; ++i) {
for (int j = 1; j <= b.m; ++j) {
res.a[i][j] = (res.a[i][j] + a.a[i][k] * b.a[k][j]) % mod;
}
}
}
return res;
}
inline ll det(mat A) {
ll ans = 1, n = A.n;
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
if (A.a[j][i]) {
if (i != j) {
swap(A.a[i], A.a[j]);
ans = (mod - ans) % mod;
}
break;
}
}
if (!A.a[i][i]) {
return 0;
}
ans = ans * A.a[i][i] % mod;
ll t = qpow(A.a[i][i], mod - 2);
for (int j = i; j <= n; ++j) {
A.a[i][j] = A.a[i][j] * t % mod;
}
for (int j = 1; j <= n; ++j) {
if (i == j) {
continue;
}
ll t = (mod - A.a[j][i]) % mod;
for (int k = i + 1; k <= n; ++k) {
A.a[j][k] = (A.a[j][k] + t * A.a[i][k]) % mod;
}
}
}
return ans;
}
void solve() {
scanf("%lld", &n);
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
for (int i = 1; i < n; ++i) {
scanf("%lld", &b[i]);
}
A = mat(a[1], a[1]);
for (int i = 1; i <= a[1]; ++i) {
A.a[i][i] = 1;
}
for (int i = 1; i < n; ++i) {
mat B(a[i], a[i + 1]);
for (int _ = 0, u, v; _ < b[i]; ++_) {
scanf("%d%d", &u, &v);
B.a[u][v] = 1;
}
A = A * B;
}
printf("%lld\n", det(A));
}
int main() {
int T = 1;
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}