int n, m, t, ans; int a[kMaxN][kMaxN], ps[kMaxN][kMaxN], cnt[kMaxN], p[kMaxN], pos[kMaxN]; int gg[kMaxN][kMaxN][kMaxN][2];
intqpow(int bs, int64_t idx = kMod - 2){ int ret = 1; for (; idx; idx >>= 1, bs = (int64_t)bs * bs % kMod) if (idx & 1) ret = (int64_t)ret * bs % kMod; return ret; }
inlineintadd(int x, int y){ return (x + y >= kMod ? x + y - kMod : x + y); } inlineintsub(int x, int y){ return (x >= y ? x - y : x - y + kMod); } inlinevoidinc(int &x, int y){ (x += y) >= kMod ? x -= kMod : x; } inlinevoiddec(int &x, int y){ (x -= y) < 0 ? x += kMod : x; }
intcheck(){ int ret = 2; for (int i = 1; i <= m; ++i) { // int cnt = 0; // for (int j = 1; j < n; ++j) cnt += (pos[a[i][j]] > pos[a[i][j + 1]]); if (cnt[i] > 1) return0; if (cnt[i] == 0) ret = 1; } return ret; }
voidgetcnt(){ staticint f[kMaxN][kMaxN], cut[kMaxN]; if (t == n) returninc(ans, 1); for (int i = 1; i <= m; ++i) { cut[i] = 0; for (int j = 1; j < n; ++j) { int v1 = pos[a[i][j]], v2 = pos[a[i][j + 1]]; if (v1 && v2 && v1 > v2 || !v1 && v2) assert(!cut[i]), cut[i] = j; } assert(cut[i]); } memset(f, 0, sizeof(f)); int ss = 0, tt = cut[1]; for (int i = 1; i <= n; ++i) { int v1 = pos[a[1][i]], v2 = pos[a[1][i + 1]]; if (v1 && !v2) { if (i <= cut[1]) ss = i; else tt = i; } } if (!ss && pos[a[1][cut[1]]]) ss = cut[1]; // std::cerr << t << " : "; // for (int i = 1; i <= t; ++i) std::cerr << p[i] << " \n"[i == t]; f[ss][tt] = 1; // std::cerr << "shabi " << ss << ' ' << tt << ' ' << cut[1] << '\n'; for (int i = ss; i <= cut[1]; ++i) { for (int j = tt; j <= n; ++j) { if (!f[i][j]) continue; int x = 0, y = 0; bool fl1 = 0, fl2 = 0; if (i < cut[1]) x = a[1][i + 1], fl1 = 1; if (j < n) y = a[1][j + 1], fl2 = 1; if (x) assert(!pos[x]); if (y) assert(!pos[y]); // std::cerr << "shabi " << i << ' ' << j << ' ' << x << ' ' << y << '\n'; for (int k = 2; k <= m; ++k) { if (fl1) { int p = ps[k][x], v = a[k][p - 1]; if (v && (ps[1][v] > i && ps[1][v] <= cut[1] || ps[1][v] > j)) fl1 = 0; } if (fl2) { int p = ps[k][y], v = a[k][p - 1]; if (v && (ps[1][v] > i && ps[1][v] <= cut[1] || ps[1][v] > j)) fl2 = 0; } } if (fl1) inc(f[i + 1][j], f[i][j]); if (fl2) inc(f[i][j + 1], f[i][j]); // if (fl2) std::cerr << "sbbb " << i << ' ' << j << ' ' << y << ' ' << ps[1][a[2][ps[2][y] - 1]] << '\n'; } } // std::cerr << "fuck " << f[cut[1]][n] << ' ' << cut[1] << ' ' << cut[2] << ' ' << cut[3] << '\n'; // std::cerr << "fuck " << cut[2] << ' ' << f[cut[1]][n] << ' ' << pos[1] << ' ' << pos[2] << ' ' << pos[3] << '\n'; inc(ans, f[cut[1]][n]); }
voiddfs(){ int fl = check(); if (!fl) return; elseif (t == n || fl == 2) returngetcnt(); for (int i = 1; i <= n; ++i) { if (pos[i]) continue; p[++t] = i, pos[i] = t; for (int j = 1; j <= m; ++j) cnt[j] += (ps[j][i] > 1 && !pos[a[j][ps[j][i] - 1]]); dfs(); --t, pos[i] = 0; for (int j = 1; j <= m; ++j) cnt[j] -= (ps[j][i] > 1 && !pos[a[j][ps[j][i] - 1]]); } }
intsolve(int n, int m, std::vector<std::vector<int>>& splits){ ::n = n, ::m = m; for (int i = 1; i <= m; ++i) for (int j = 1; j <= n; ++j) ps[i][a[i][j] = splits[i - 1][j - 1]] = j; dfs(); // p[++t] = 2, pos[2] = 1; // getcnt(); // p[++t] = 2, p[++t] = 3; // pos[2] = 1, pos[3] = 2; // getcnt(); return ans; }