题意:输入2个字符矩阵 求第二个字符矩阵在第一个字符矩阵中出现的次数
思路:见大白书218页
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 1010;
const int maxm = 110;
char a[maxn][maxn];
char b[maxm][maxm];
int cnt[maxn][maxn];
int n, m, x, y;
const int maxnode = 1000*1000+100;
const int size = 26;
int val[maxnode];
int ch[maxnode][size];
int f[maxnode];
int last[maxnode];
int sz;
vector <int> G[maxnode];
void init()
{
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
memset(cnt, 0, sizeof(cnt));
val[0] = 0;
last[0] = 0;
G[0].clear();
memset(f, 0, sizeof(f));
}
void insert(char *s, int v)
{
int u = 0;
for(int i = 0; i < y; i++)
{
int c = s[i] - 'a';
if(!ch[u][c])
{
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
G[sz].clear();
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u]++;
G[u].push_back(v);
}
void getFail()
{
queue <int> Q;
f[0] = 0;
for(int c = 0; c < size; c++)
{
int u = ch[0][c];
if(u)
{
f[u] = 0;
Q.push(u);
}
}
while(!Q.empty())
{
int r = Q.front(); Q.pop();
for(int c = 0; c < size; c++)
{
int u = ch[r][c];
if(!u)
{
ch[r][c] = ch[f[r]][c];
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()
{
for(int i = 0; i < n; i++)
{
int u = 0;
for(int j = 0; j < m; j++)
{
int c = a[i][j] - 'a';
u = ch[u][c];
if(!val[u] && !last[u])
continue;
int v = val[u] ? u : last[u];
while(v)
{
for(int k = 0; k < G[v].size(); k++)
{
if(i-G[v][k] >= 0)
cnt[i-G[v][k]][j-y+1]++;
}
v = last[v];
}
}
}
int ans = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(cnt[i][j] == x)
ans++;
printf("%d\n", ans);
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
init();
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++)
{
scanf("%s", a[i]);
}
scanf("%d %d", &x, &y);
for(int i = 0; i < x; i++)
{
scanf("%s", b[i]);
insert(b[i], i);
}
getFail();
find();
}
return 0;
}
/*
2
1 1
x
1 1
y
3 3
abc
bcd
cde
2 2
bc
cd
*/