AC自动机。
很容易想到一个思路将模式矩阵的每一行插入Tire,然后将匹配矩阵的每一行用AC自动机漫游,统计该行中出现过的模式矩阵行,最后判断出现过的每行是否能够组成整个模式矩阵即可。这个也很好判断。开一个数组flag【i】【j】【k】表示字符【i,j】是第k个字符串的末尾
但是有个问题如果模式矩阵中的串有重复,比如说
匹配阵是
aaa
aaa
aaa
模式矩阵
aa
aa
那么很有可能得不到正确结果。
所以我把AC自动机中的val数组改成了二维,来表示某个字符可能是多个重复字符串的末尾。
注意是字符矩阵,所以只用26个小写字母是不行的。至少得128.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#define ll long long
#define INF 2139062143
#define inf -2139062144
#define MOD 20071027
#define MAXN 101*100
#define LIM 128
using namespace std;
char gl1[1005][1005],gl2[105][105];
bool flag[1005][1005][101];
int now,ans;
int nx,ny,mx,my;
struct Tire
{
int ch[MAXN][LIM],last[MAXN],f[MAXN];
vector<int> val[MAXN];
int sz;
void clear()
{
sz=1;
memset(ch[0],0,sizeof(ch[0]));
val[0].clear();
}
void insert(char *word,int v)
{
int u=0;
for(int i=0; word[i]; ++i)
{
int c=word[i];
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
val[sz].clear();
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u].push_back(v);
}
void process(int i,int j)
{
if(j)
{
for(int k=0; k<val[j].size(); ++k)
{
int v=val[j][k];
if(v==1||flag[now-1][i+1][v-1]==true)
{
flag[now][i+1][v]=true;
if(v==mx) ans++;
}
}
process(i,last[j]);
}
}
void find(char *str)
{
int j=0;
for(int i=0; str[i]; ++i)
{
int c=str[i];
j=ch[j][c];
if(val[j].size()) process(i,j);
else if(last[j]) process(i,last[j]);
}
}
void getFail()
{
f[0]=0;
queue<int> que;
for(int i=0; i<LIM; ++i)
{
int u=ch[0][i];
if(u)
{
f[u]=0;
last[u]=0;
que.push(u);
}
}
while(!que.empty())
{
int q=que.front();
que.pop();
for(int i=0; i<LIM; ++i)
{
int u=ch[q][i], v=f[q];
if(!u)
{
ch[q][i]=ch[v][i];
continue;
}
que.push(u);
while(v&&!ch[v][i]) v=ch[v][i];
f[u]=ch[v][i];
last[u]=val[f[u]].size()?f[u]:last[f[u]];
}
}
}
};
Tire tree;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
tree.clear();
scanf("%d%d",&nx,&ny);
for(int i=1; i<=nx; ++i)
{
scanf("%s",gl1[i]+1);
memset(flag[i],0,sizeof(flag[i]));
}
scanf("%d%d",&mx,&my);
for(int i=1; i<=mx; ++i)
{
scanf("%s",gl2[i]+1);
tree.insert(gl2[i]+1,i);
}
tree.getFail();
ans=0;
for(int i=1; i<=nx; ++i)
{
now=i;
tree.find(gl1[i]+1);
}
printf("%d\n",ans);
}
return 0;
}