AC自动机(二维) UVA 11019 Matrix Matcher

时间:2022-01-06 23:33:44

题目传送门

题意:训练指南P218

分析:一行一行的插入,一行一行的匹配,当匹配成功时将对应子矩阵的左上角位置cnt[r][c]++;然后统计 cnt[r][c] == x 的数量

#include <bits/stdc++.h>
using namespace std; const int N = 1e3 + 5;
const int NODE = 1e4 + 5;
const int SIZE = 26;
char mat1[N][N], mat2[105][105];
int cnt[N][N];
int n, m, x, y;
struct AC {
int ch[NODE][SIZE], val[NODE], sz;
int fail[NODE], last[NODE];
vector<int> rows[NODE];
void clear(void) {
memset (ch[0], 0, sizeof (ch[0]));
sz = 1;
for (int i=0; i<NODE; ++i) rows[i].clear ();
}
int idx(char c) {
return c - 'a';
}
void insert(char *P, int v) {
int u = 0;
for (int c, i=0; P[i]; ++i) {
c = idx (P[i]);
if (!ch[u][c]) {
memset (ch[sz], 0, sizeof (ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
rows[u].push_back (v);
}
void build(void) {
queue<int> que; fail[0] = 0;
int u;
for (int c=0; c<SIZE; ++c) {
u = ch[0][c];
if (u) {fail[u] = 0; que.push (u);}
}
while (!que.empty ()) {
int r = que.front (); que.pop ();
for (int c=0; c<SIZE; ++c) {
int &u = ch[r][c];
if (!u) {
u = ch[fail[r]][c];
continue;
}
que.push (u);
int v = fail[r];
while (v && !ch[v][c]) v = fail[v]; //
fail[u] = ch[v][c];
last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
}
}
}
void query(int row) {
int u = 0;
for (int c, i=0; mat1[row][i]; ++i) {
c = idx (mat1[row][i]);
u = ch[u][c];
if (i - y + 1 < 0) continue;
if (val[u]) print (row, i - y + 1, u);
else if (last[u]) print (row, i - y + 1, last[u]);
}
}
void print(int r, int c, int u) {
if (u) {
for (int i=0; i<rows[u].size (); ++i) {
int tr = rows[u][i];
if (r - tr + 1 >= 1) {
cnt[r-tr+1][c]++;
}
}
print (r, c, last[u]);
}
}
}ac; int main(void) {
int T; scanf ("%d", &T);
while (T--) {
scanf ("%d%d", &n, &m);
for (int i=1; i<=n; ++i) {
scanf ("%s", &mat1[i]);
}
ac.clear ();
scanf ("%d%d", &x, &y);
for (int i=1; i<=x; ++i) {
scanf ("%s", &mat2[i]);
ac.insert (mat2[i], i);
}
ac.build ();
memset (cnt, 0, sizeof (cnt));
for (int i=1; i<=n; ++i) {
ac.query (i);
}
int ans = 0;
for (int i=1; i<=n-x+1; ++i) {
for (int j=0; j<=m-y; ++j) {
if (cnt[i][j] == x) ans++;
}
}
printf ("%d\n", ans);
} return 0;
}