题意:给一个n*m的文本串和x*y的模式串,问模式串出现几次。
思路:对模式串每一行建立Tire,设c[i][j]代表模式串p左上角在(i,j)位置上时有模式串多少行可以与文本串匹配,在文本串中每一行用AC自动机寻找,注意可能有模式串重复的情况,要用一个nxt数组,连接起所有的重复的模式串,tire上的值即为模式串的行号
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
const int maxn = 1e3 + 10;
const int maxSize = 30;
using namespace std;
char t[maxn][maxn], p[110][110];
int f[maxn*maxn], last[maxn*maxn], np;
int ch[20500][maxSize], sz;
int val[maxn*maxn], c[maxn][maxn];
int l[maxn], nxt[maxn];
int have[maxn], L[maxn];
void init() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
memset(val, 0, sizeof(val));
memset(f, 0, sizeof(f));
memset(c, 0, sizeof c);
memset(nxt, -1, sizeof nxt);
memset(have, 0, sizeof(have));
}
void build(char *s, int ii) {
int u = 0, n = strlen(s);
for(int i = 0; i < n; i++) {
int c = s[i] - 'a' + 1;
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = ii;
}
void print(int i, int j, int R) {
if(!j) return ;
int ind = val[j] - 1;
while(ind != -1) {
if(R - ind >= 0) c[R - ind][i - L[ind] + 1]++;
ind = nxt[ind];
}
print(i, last[j], R);
}
void getfail() {
queue<int> q;
f[0] = 0;
for(int c = 0; c < maxSize; c++) {
int u = ch[0][c];
if(u) { f[u] = 0; q.push(u); last[u] = 0; }
}
while(!q.empty()) {
int r = q.front(); q.pop();
for(int c = 0; c < maxSize; c++) {
int u = ch[r][c];
if(!u) continue;
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]] ? f[u] : last[f[u]];
}
}
}
void Find(char *T, int R) {
int n = l[R], j = 0;
for(int i = 0; i < n; i++) {
int c = T[i] - 'a' + 1;
while(j && !ch[j][c]) j = f[j];
j = ch[j][c];
if(val[j]) print(i, j, R);
else if(last[j]) print(i, last[j], R);
}
}
int main() {
int n, m, x, y, T;
scanf("%d", &T);
while(T--) {
init();
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++) {
scanf("%s", t[i]);
l[i] = m;
}
scanf("%d %d", &x, &y);
for(int i = 0; i < x; i++) {
scanf("%s", p[i]);
L[i] = y;
}
for(int i = 0; i < x; i++) {
for(int j = i + 1; j < x; j++) {
if(strcmp(p[i], p[j])) continue;
nxt[i] = j; have[j] = 1;
break;
}
}
for(int i = 0; i < x; i++) {
if(have[i]) continue;
build(p[i], i + 1);
}
getfail();
for(int i = 0; i < n; i++)
Find(t[i], i);
int ans = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++)
if(c[i][j] == x) ans++;
}
printf("%d\n", ans);
}
return 0;
}