kmp(exKMP)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; const int N = 1 << 20 | 10, S = 30; int T, n, z[N], pre[S], suf[S], pc, sc, sum1, sum2, tot, cnt[S]; char s[N]; long long ans; int main() { freopen("string.in", "r", stdin); freopen("string.out", "w", stdout); scanf("%d", &T); while (T--) { for (int c = 0; c < 26; c++) pre[c] = suf[c] = cnt[c] = 0; pc = sc = tot = sum1 = sum2 = ans = 0; scanf("%s", s); n = strlen(s); int l = 0, r = 0; z[0] = 0; for (int i = 1; i < n; i++) { if (i > r) { z[i] = 0; while (z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++; r = i + z[i] - 1, l = i; } else { z[i] = min(r - i + 1, z[i - l]); while (z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++; if (r < i + z[i] - 1) r = i + z[i] - 1, l = i; } } for (int i = 0; i < n; i++) suf[s[i] - 'a'] ^= 1; for (int c = 0; c < 26; c++) tot += suf[c]; sc = tot; for (int i = 1; i < n; i++) { int c = s[i - 1] - 'a', k = min(z[i], n - i - 1) / i + 1; sum1 += (suf[c] ? -cnt[sc--] : cnt[++sc]), suf[c] ^= 1; ans += (k + 1ll) / 2 * sum1; pc += (pre[c] ? -1 : 1), pre[c] ^= 1; ans += 1ll * k / 2 * sum2; cnt[pc]++; if (pc <= sc) sum1++; if (pc <= tot) sum2++; } cout << ans << endl; } return 0; }
字典树
ac自动机
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define eps 1e-3 #define inf 1e18 using namespace std; const int N = 1510; int n, m, sze[N], nodeid, tr[N][10], fa[N]; double val[N]; char t[N], s[N], p[N]; void ins(char *str, double v) { int u = 0; for (int i = 0; str[i]; i++) { int c = str[i] - '0'; if (!tr[u][c]) tr[u][c] = ++nodeid; u = tr[u][c]; } sze[u]++, val[u] += v; } int head[N], to[N], nxt[N], cnt; void add_edge(int u, int v) { to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt; } void dfs(int u) { sze[u] += sze[fa[u]], val[u] += val[fa[u]]; for (int i = head[u]; i; i = nxt[i]) dfs(to[i]); } queue<int> q; void build() { for (int c = 0; c < 10; c++) if (tr[0][c]) q.push(tr[0][c]); while (!q.empty()) { int u = q.front(); q.pop(); for (int c = 0; c < 10; c++) if (tr[u][c]) fa[tr[u][c]] = tr[fa[u]][c], q.push(tr[u][c]); else tr[u][c] = tr[fa[u]][c]; } for (int i = 1; i <= nodeid; i++) add_edge(fa[i], i); dfs(0); } double f[N][N]; int las[N][N], col[N][N]; double check(double mid) { for (int i = 1; i <= nodeid; i++) val[i] -= mid * sze[i]; for (int i = 0; i <= n; i++) for (int j = 0; j <= nodeid; j++) f[i][j] = -inf; f[0][0] = 0; for (int i = 0; i < n; i++) for (int u = 0; u <= nodeid; u++) { if (f[i][u] == -inf) continue; if (t[i + 1] == '.') { for (int c = 0; c < 10; c++) { int v = tr[u][c]; if (f[i + 1][v] < f[i][u] + val[v]) { f[i + 1][v] = f[i][u] + val[v]; las[i + 1][v] = u, col[i + 1][v] = c; } } } else { int v = tr[u][t[i + 1] - '0']; if (f[i + 1][v] < f[i][u] + val[v]) { f[i + 1][v] = f[i][u] + val[v]; las[i + 1][v] = u, col[i + 1][v] = t[i + 1] - '0'; } } } for (int i = 1; i <= nodeid; i++) val[i] += mid * sze[i]; int ans = 0; for (int i = 1; i <= nodeid; i++) if (f[n][i] > f[n][ans]) ans = i; for (int u = ans, i = n; i >= 1; u = las[i][u], i--) p[i] = col[i][u] + '0'; return f[n][ans]; } int main() { scanf("%d%d", &n, &m); scanf("%s", t + 1); for (int i = 1; i <= m; i++) { double v; scanf("%s%lf", s, &v); ins(s, log(v)); } build(); double l = 0, r = log(1e9 + 5), ans = 0; while (r - l > eps) { double mid = (l + r) / 2; if (check(mid) > 0) ans = mid, l = mid; else r = mid; } check(ans); for (int i = 1; i <= n; i++) putchar(p[i]); return 0; }
manacher
想了个manacher+hash+二分的方法,写到一半困死了就鸽惹
回文自动机
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define Mod 1000000007 using namespace std; const int N = 1e6 + 10; int n, fa[N], tr[N][26], len[N], d[N], pre[N], las, nodeid, dp[N], g[N]; char s[N], t[N]; void ins(int c, int m) { int u = las; while (t[m - len[u] - 1] != t[m]) u = fa[u]; int now = tr[u][c]; if (!now) { now = ++nodeid; int v = fa[u]; while (t[m - len[v] - 1] != t[m]) v = fa[v]; fa[now] = tr[v][c]; tr[u][c] = now; len[now] = len[u] + 2; d[now] = len[now] - len[fa[now]]; if (d[now] == d[fa[now]]) pre[now] = pre[fa[now]]; else pre[now] = fa[now]; } las = now; } inline int M(const int &o) { return o >= Mod ? o - Mod : o; } int main() { scanf("%s", s + 1); n = strlen(s + 1); if (n & 1) return puts("0"), 0; for (int i = 1; (i << 1) <= n; i++) t[i * 2 - 1] = s[i], t[i * 2] = s[n - i + 1]; fa[0] = fa[1] = 1, len[0] = 0, len[1] = -1, nodeid = 1; dp[0] = 1; for (int i = 1; i <= n; i++) { ins(t[i] - 'a', i); for (int j = las; j > 1; j = pre[j]) { g[j] = dp[i - len[pre[j]] - d[j]]; if (d[j] == d[fa[j]]) g[j] = M(g[j] + g[fa[j]]); if (!(i & 1)) dp[i] = M(dp[i] + g[j]); } } cout << dp[n] << endl; return 0; }
后缀数组
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; const int N = 3e4 + 10; int T, n, m, sa[N], tax[N], rak[N << 1], tmp[N << 1], num, height[N], Min[15][N], Log[N]; char s[N]; void rsort() { for (int i = 1; i <= m; i++) tax[i] = 0; for (int i = 1; i <= n; i++) tax[rak[i]]++; for (int i = 1; i <= m; i++) tax[i] += tax[i - 1]; for (int i = n; i >= 1; i--) sa[tax[rak[tmp[i]]]--] = tmp[i]; } void init() { memset(rak, 0, sizeof(rak)); memset(tmp, 0, sizeof(tmp)); // 不能只清空到n for (int i = 1; i <= n; i++) rak[i] = s[i] - 'a' + 1, tmp[i] = i, sa[i] = 0; m = 26, rsort(); for (int len = 1, p = 0; p < n; m = p, len <<= 1) { num = 0; for (int i = n - len + 1; i <= n; i++) tmp[++num] = i; for (int i = 1; i <= n; i++) if (sa[i] > len) tmp[++num] = sa[i] - len; rsort(), swap(rak, tmp); rak[sa[1]] = p = 1; for (int i = 2; i <= n; i++) rak[sa[i]] = (tmp[sa[i]] == tmp[sa[i - 1]] && tmp[sa[i] + len] == tmp[sa[i - 1] + len] ? p : ++p); // 注意该行后面有sa[i]+len与sa[i-1]+len } int l = 0; for (int i = 1; i <= n; i++) { if (l) l--; int j = sa[rak[i] - 1]; while (i + l <= n && j + l <= n && s[i + l] == s[j + l]) l++; height[rak[i]] = l; } Log[0] = -1; for (int i = 1; i <= n; i++) Min[0][i] = height[i], Log[i] = Log[i >> 1] + 1; for (int k = 1; (1 << k) <= n; k++) for (int i = 1; i + (1 << k) - 1 <= n; i++) Min[k][i] = min(Min[k - 1][i], Min[k - 1][i + (1 << (k - 1))]); } inline int MIN(const int &l, const int &r) { int t = Log[r - l + 1]; return min(Min[t][l], Min[t][r - (1 << t) + 1]); } vector<int> lcp0[N], lcp1[N], lcs0[N], lcs1[N]; int lcnt[N], rcnt[N]; long long ans; int main() { scanf("%d", &T); while (T--) { scanf("%s", s + 1); n = strlen(s + 1); init(); ans = 0; for (int i = 1; i <= n; i++) lcnt[i] = rcnt[i] = 0; for (int len = 1; (len << 1) <= n; len++) { lcp0[len].resize(n / len + 2); lcp1[len].resize(n / len + 2); for (int i = 1; (i + 1) * len <= n; i++) { int l = rak[i * len], r = rak[i * len + len]; if (l > r) swap(l, r); lcp0[len][i] = lcp1[len][i + 1] = min(len, MIN(l + 1, r)); } } for (int i = 1; (i << 1) <= n; i++) swap(s[i], s[n - i + 1]); init(); for (int len = 1; (len << 1) <= n; len++) { lcs0[len].resize(n / len + 2); lcs1[len].resize(n / len + 2); for (int i = 1; (i + 1) * len <= n; i++) { int l = rak[n - i * len + 1], r = rak[n - i * len - len + 1]; if (l > r) swap(l, r); lcs0[len][i] = lcs1[len][i + 1] = min(len, MIN(l + 1, r)); } } for (int len = 1; (len << 1) <= n; len++) { for (int i = 1; (i + 1) * len <= n; i++) { int l = (i + 1) * len - lcs1[len][i + 1] + len, r = (i + 1) * len + lcp1[len][i + 1] - 1; if (l <= r) lcnt[l]++, lcnt[r + 1]--; l = i * len - lcs0[len][i] + 1, r = i * len + lcp0[len][i] - len; if (l <= r) rcnt[l]++, rcnt[r + 1]--; } } for (int i = 1; i <= n; i++) lcnt[i] += lcnt[i - 1], rcnt[i] += rcnt[i - 1]; for (int i = 1; i < n; i++) ans += 1ll * lcnt[i] * rcnt[i + 1]; cout << ans << endl; } return 0; }
后缀自动机
SAM+线段树合并
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < '0' || cc > '9') { if (cc == '-') flag = true; cc = getchar(); } while (cc >= '0' && cc <= '9') { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } inline void write(ll x, char ch) { if (x < 0) putchar('-'), x = -x; if (x == 0) putchar('0'); else { int num = 0; char cc[22]; while (x) cc[++num] = x % 10 + 48, x /= 10; while (num) putchar(cc[num--]); } putchar(ch); } const int L = 5e5 + 10, N = 1e6 + 10; int rt[N], ls[N * 40], rs[N * 40], sum[N * 40], tot, Left, Right; void add(int &u, int l, int r, int pos) { if (!u) u = ++tot; if (l == r) sum[u]++; else { int mid = (l + r) >> 1; if (pos <= mid) add(ls[u], l, mid, pos); else add(rs[u], mid + 1, r, pos); sum[u] = sum[ls[u]] + sum[rs[u]]; } } void merge(int &u, int x, int y) { if (!x || !y) u = (x | y); else { u = ++tot; merge(ls[u], ls[x], ls[y]), merge(rs[u], rs[x], rs[y]); sum[u] = sum[ls[u]] + sum[rs[u]]; } } int find(int u, int l, int r) { if (!u || !sum[u]) return -1; if (l == r) return l; int mid = (l + r) >> 1, pos = -1; if (mid < Right) pos = find(rs[u], mid + 1, r); if (pos == -1 && Left <= mid) pos = find(ls[u], l, mid); return pos; } int n, m, tax[L], ord[N], ed[L]; char s[L], t[L]; ll ans; struct sam { int trans[N][26], fa[N], len[N], las, nodeid; void init() { for (int c = 0; c < 26; c++) trans[0][c] = 1; for (int u = 1; u <= nodeid; u++) for (int c = 0; c < 26; c++) trans[u][c] = 0; las = nodeid = 1; } void ins(int c) { int p = las, np = ++nodeid; len[np] = len[p] + 1; for ( ; p && !trans[p][c]; p = fa[p]) trans[p][c] = np; if (!p) fa[np] = 1; else { int q = trans[p][c]; if (len[q] == len[p] + 1) fa[np] = q; else { int nq = ++nodeid; len[nq] = len[p] + 1; for (int i = 0; i < 26; i++) trans[nq][i] = trans[q][i]; fa[nq] = fa[q], fa[q] = fa[np] = nq; for ( ; p && trans[p][c] == q; p = fa[p]) trans[p][c] = nq; } } las = np; } void build() { for (int i = 1; i <= nodeid; i++) tax[len[i]]++; for (int i = 1; i <= n; i++) tax[i] += tax[i - 1]; for (int i = 1; i <= nodeid; i++) ord[tax[len[i]]--] = i; for (int i = nodeid; i; i--) { int now = ord[i]; if (now != 1) merge(rt[fa[now]], rt[fa[now]], rt[now]); } } } ss, st; int main() { freopen("name.in", "r", stdin); freopen("name.out", "w", stdout); scanf("%s", s + 1), n = strlen(s + 1); ss.init(); for (int i = 1; i <= n; i++) ss.ins(s[i] - 'a'), ed[i] = ss.las; for (int i = 1; i <= n; i++) add(rt[ed[i]], 1, n, i); ss.build(); for (int T = read(); T; T--) { scanf("%s", t + 1), m = strlen(t + 1); Left = read(), Right = read(), ans = 0; st.init(); int now = 1, l = 0; for (int i = 1; i <= m; i++) { int c = t[i] - 'a'; st.ins(c); while (now && !ss.trans[now][c]) now = ss.fa[now], l = ss.len[now]; now = ss.trans[now][c], l += (now != 1); //cout << now << " " << l << " ----------------------------- "; int pos = -1; while (now > 1) { pos = find(rt[now], 1, n); //cout << pos << " "; if (pos == -1 || pos - ss.len[ss.fa[now]] < Left) now = ss.fa[now], l = ss.len[now]; else break; } //cout << pos << "," << now << "," << l << " =================== "; int mat = (pos == -1 ? 0 : min(l, pos - Left + 1)); ans += max(0, st.len[st.las] - max(mat, st.len[st.fa[st.las]])); } write(ans, ' '); } return 0; }
后缀树与lct的结合
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int L = 1e5 + 10, N = 2e5 + 10; int n, m, fa[N], nodeid = 1, trans[N][26], len[N], las = 1, p[L]; char s[L]; void ins(int c) { int p = las, np = ++nodeid; len[np] = len[p] + 1; for ( ; p && !trans[p][c]; p = fa[p]) trans[p][c] = np; if (!p) fa[np] = 1; else { int q = trans[p][c]; if (len[q] == len[p] + 1) fa[np] = q; else { int nq = ++nodeid; len[nq] = len[p] + 1; for (int k = 0; k < 26; k++) trans[nq][k] = trans[q][k]; fa[nq] = fa[q], fa[q] = fa[np] = nq; for ( ; p && trans[p][c] == q; p = fa[p]) trans[p][c] = nq; } } las = np; } // sam #define lson u << 1, l, mid #define rson u << 1 | 1, mid + 1, r ll sum[L << 2], tag[L << 2], ans[N]; void pushdown(int u, int len) { sum[u << 1] += 1ll * tag[u] * (len - (len >> 1)); sum[u << 1 | 1] += 1ll * tag[u] * (len >> 1); tag[u << 1] += tag[u], tag[u << 1 | 1] += tag[u]; tag[u] = 0; } void modify(int u, int l, int r, int Left, int Right, int delta) { //cout << u << ' ' << l << ' ' << r << " " << Left << " " << Right << endl; if (Left <= l && r <= Right) sum[u] += delta * (r - l + 1ll), tag[u] += delta; else { int mid = (l + r) >> 1; pushdown(u, r - l + 1); if (Left <= mid) modify(lson, Left, Right, delta); if (mid < Right) modify(rson, Left, Right, delta); sum[u] = sum[u << 1] + sum[u << 1 | 1]; } } ll query(int u, int l, int r, int Left, int Right) { if (Left <= l && r <= Right) return sum[u]; int mid = (l + r) >> 1; ll res = 0; pushdown(u, r - l + 1); if (Left <= mid) res += query(lson, Left, Right); if (mid < Right) res += query(rson, Left, Right); return res; } // segment_tree #define check(x) (tr[fa[x]][1] == x) #define isroot(x) (tr[fa[x]][0] != x && tr[fa[x]][1] != x) int tr[N][2], id[N]; void pushdown(int u) { if (id[u]) { if (tr[u][0]) id[tr[u][0]] = id[u]; if (tr[u][1]) id[tr[u][1]] = id[u]; } } void pushall(int u) { if (fa[u]) pushall(fa[u]); pushdown(u); } void rotate(int x) { int y = fa[x], z = fa[y], opt1 = check(x), opt2 = check(y); if (!isroot(y)) tr[z][opt2] = x; fa[x] = z; tr[y][opt1] = tr[x][opt1 ^ 1], fa[tr[x][opt1 ^ 1]] = y; tr[x][opt1 ^ 1] = y, fa[y] = x; } void splay(int x) { pushall(x); while (!isroot(x)) { int y = fa[x]; if (!isroot(y)) rotate(check(x) == check(y) ? y : x); rotate(x); } } void access(int x, int ed) { int u = x; for (int y = 0; x; y = x, x = fa[x]) { splay(x), tr[x][1] = y; if (id[x]) modify(1, 1, n, id[x] - len[x] + 1, id[x] - len[fa[x]], -1); } splay(u), modify(1, 1, n, 1, id[u] = ed, 1); } // lct struct que { int l, r, id; bool operator < (const que &g) const { return r < g.r; } } q[N]; int main() { scanf("%s", s + 1); n = strlen(s + 1); for (int i = 1; i <= n; i++) ins(s[i] - 'a'), p[i] = las; //for (int i = 1; i <= nodeid; i++) cout << i << " " << p[i] << " " << len[i] << ' ' << fa[i] << " "; scanf("%d", &m); for (int i = 1; i <= m; i++) scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i; sort(q + 1, q + m + 1); int now = 0; for (int i = 1; i <= m; i++) { while (now < q[i].r) ++now, access(p[now], now); ans[q[i].id] = query(1, 1, n, q[i].l, q[i].r); } //printf("(%d) ", nodeid); for (int i = 1; i <= m; i++) printf("%lld ", ans[i]); return 0; }
哈希
splay+hash(自然溢出)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define check(x) (tr[fa[x]][1] == x) using namespace std; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < '0' || cc > '9') { if (cc == '-') flag = true; cc = getchar(); } while (cc >= '0' && cc <= '9') { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } inline void write(int x, char ch) { if (x < 0) putchar('-'), x = -x; if (x == 0) putchar('0'); else { int num = 0; char cc[22]; while (x) cc[++num] = x % 10 + 48, x /= 10; while (num) putchar(cc[num--]); } putchar(ch); } const int N = 100010; int n, q, rt, nodeid, tr[N][2], sze[N], fa[N]; unsigned int arr[N], val[N], p[N]; char ch; void updata(int u) { sze[u] = sze[tr[u][0]] + sze[tr[u][1]] + 1; val[u] = val[tr[u][0]] * p[sze[tr[u][1]] + 1] + arr[u] * p[sze[tr[u][1]]] + val[tr[u][1]]; } void rotate(int x) { int y = fa[x], z = fa[y], opt1 = check(x), opt2 = check(y); fa[x] = z, tr[z][opt2] = x; fa[tr[x][opt1 ^ 1]] = y, tr[y][opt1] = tr[x][opt1 ^ 1]; fa[y] = x, tr[x][opt1 ^ 1] = y; updata(y), updata(x); } void splay(int x, int goal) { updata(x); while (fa[x] != goal) { int y = fa[x], z = fa[y]; if (z != goal) rotate(check(x) == check(y) ? y : x); rotate(x); } if (!goal) rt = x; } int find(int k) { if (k == 0) return 0; int u = rt; while (true) { if (k > sze[tr[u][0]] + 1) k -= sze[tr[u][0]] + 1, u = tr[u][1]; else if (k <= sze[tr[u][0]]) u = tr[u][0]; else return u; } } void ins(int k, int c) { int u = find(k), par = u, v = tr[par][1]; while (v) par = v, v = tr[par][0]; v = ++nodeid, sze[v] = 1, arr[v] = c; fa[v] = par, tr[par][par == u ? 1 : 0] = v, splay(v, 0); } void change(int k, int c) { int u = find(k); arr[u] = c, splay(u, 0); } unsigned int query(int l, int r) { if (l == 1 && r == n) return val[rt]; if (l == 1) return splay(find(r + 1), 0), val[tr[rt][0]]; if (r == n) return splay(find(l - 1), 0), val[tr[rt][1]]; int x = find(l - 1), y = find(r + 1); splay(x, 0), splay(y, x); return val[tr[y][0]]; } int main() { p[0] = 1; for (int i = 1; i < N; i++) p[i] = p[i - 1] * 29u; ch = getchar(); while (ch < 'a' || ch > 'z') ch = getchar(); while (ch >= 'a' && ch <= 'z') ins(n++, ch - 'a'), ch = getchar(); for (q = read(); q; q--) { ch = getchar(); while (ch != 'Q' && ch != 'R' && ch != 'I') ch = getchar(); if (ch == 'Q') { int x = read(), y = read(); int l = 0, r = n - max(x, y), ans = -1; while (l <= r) { int mid = (l + r) >> 1; if (query(x, x + mid) == query(y, y + mid)) l = mid + 1, ans = mid; else r = mid - 1; } write(ans + 1, ' '); } else if (ch == 'R') { int x = read(); ch = getchar(); while (ch < 'a' || ch > 'z') ch = getchar(); change(x, ch - 'a'); } else { int x = read(); ch = getchar(); while (ch < 'a' || ch > 'z') ch = getchar(); ins(x, ch - 'a'); n++; } } return 0; }
表达式树(这个不知道该归哪一个,就把它当字符串吧233)
改为计算每个数在所有方案中被算了几次
最关键的在于这样一个结论
同行不同列的两个元素(共$m$行$n$列)
若它们各自所在列中大于等于它的元素的行号集合相同 则它们被计算次数相同
这样就有个$Theta(2^{m-1}m|E|)$的做法
然后我们可以不必枚举行号,最后$geq x$的减去$> x$的就可以了
这样是$Theta(2^{m}|E|)$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define Mod 1000000007 using namespace std; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < '0' || cc > '9') { if (cc == '-') flag = true; cc = getchar(); } while (cc >= '0' && cc <= '9') { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } inline void write(int x, char ch) { if (x < 0) putchar('-'), x = -x; if (x == 0) putchar('0'); else { int num = 0; char cc[22]; while (x) cc[++num] = x % 10 + 48, x /= 10; while (num) putchar(cc[num--]); } putchar(ch); } int n, m, a[10][50010], len, stk[50010], tp, nodeid; char s[50010], str[50010], tot, sgn[50010]; int rt, ls[50010], rs[50010], sze[50010][2], f[1024], ans; void dfs(int u, int mask) { if ('0' <= sgn[u] && sgn[u] <= '9') sze[u][(mask >> (sgn[u] - '0')) & 1]++; else { dfs(ls[u], mask), dfs(rs[u], mask); int l0 = sze[ls[u]][0], l1 = sze[ls[u]][1]; int r0 = sze[rs[u]][0], r1 = sze[rs[u]][1]; if (sgn[u] != '>') { sze[u][0] += (1ll * (l0 + l1) * (r0 + r1) - 1ll * l1 * r1) % Mod; sze[u][1] += 1ll * l1 * r1 % Mod; } if (sgn[u] != '<') { sze[u][0] += 1ll * l0 * r0 % Mod; sze[u][1] += (1ll * (l0 + l1) * (r0 + r1) - 1ll * l0 * r0) % Mod; } if (sze[u][0] >= Mod) sze[u][0] -= Mod; if (sze[u][1] >= Mod) sze[u][1] -= Mod; } } int main() { n = read(), m = read(); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) a[i][j] = read(); scanf("%s", s), len = strlen(s); for (int i = 0; i < len; i++) { if ('0' <= s[i] && s[i] <= '9') stk[++tp] = ++nodeid, sgn[nodeid] = s[i]; else { if (s[i] == '(') str[++tot] = '('; else if (s[i] == ')') { while (str[tot] != '(') { sgn[++nodeid] = str[tot--]; int x = stk[tp--], y = stk[tp--]; stk[++tp] = nodeid; ls[nodeid] = x, rs[nodeid] = y; } tot--; } else { while (tot && str[tot] != '(') { sgn[++nodeid] = str[tot--]; int x = stk[tp--], y = stk[tp--]; stk[++tp] = nodeid; ls[nodeid] = x, rs[nodeid] = y; } str[++tot] = s[i]; } } } while (tot) { sgn[++nodeid] = str[tot--]; int x = stk[tp--], y = stk[tp--]; stk[++tp] = nodeid; ls[nodeid] = x, rs[nodeid] = y; } // build expression tree rt = stk[1]; for (int mask = 0; mask < (1 << m); mask++) { for (int i = 1; i <= nodeid; i++) sze[i][0] = sze[i][1] = 0; dfs(rt, mask); f[mask] = sze[rt][1]; } // dp for (int j = 0; j < n; j++) { int q[11]; q[m] = 0x3f3f3f3f; for (int i = 0; i < m; i++) q[i] = a[i][j]; sort(q, q + m); for (int i = 0; i < m; i++) if (q[i] != q[i + 1]) { int now = 0, nxt = 0; for (int k = 0; k < m; k++) now |= ((a[k][j] >= q[i]) << k), nxt |= ((a[k][j] >= q[i + 1]) << k); ans = (ans + 1ll * (f[now] - f[nxt]) * q[i]) % Mod; } } write(ans, ' '); return 0; }