UVA11019 Matrix Matcher

时间:2021-12-16 23:35:25

思路

AC自动机匹配二维模式串的题目

因为如果矩形匹配,则每一行都必须匹配,考虑对于一个点,设count[i][j]记录以它为左上角的与模式矩形大小相同的矩形中有多少行和模式矩形匹配

然后把模式矩形的每一行插入AC自动机中,把文本矩形的每一行在上面跑,如果文本矩形第i行和模式矩形第c行匹配,匹配位置是j,则更新 counts[i-c+1][j+1-y+1]

最后每个count[i][j]等于x的(i,j)就是一个符合条件的点

小心重复的模式串。

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
int Trie[10100][26],fail[10100],counts[1010][1010],root,Nodecnt,x,y,n,m;
char s[1010][1010],t[110][110];
vector<int> isend[10100];
void insert(char *s,int len,int inq){
int o=root;
for(int i=0;i<len;i++){
if(!Trie[o][s[i]-'a'])
Trie[o][s[i]-'a']=++Nodecnt;
o=Trie[o][s[i]-'a'];
}
isend[o].push_back(inq);
}
queue<int> q;
void build_AC(void){
for(int i=0;i<26;i++){
if(Trie[root][i]){
fail[Trie[root][i]]=root;
q.push(Trie[root][i]);
}
}
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<26;i++){
if(Trie[x][i]){
fail[Trie[x][i]]=Trie[fail[x]][i];
q.push(Trie[x][i]);
}
else
Trie[x][i]=Trie[fail[x]][i];
}
}
}
void query(char *s,int len,int inq){
int o=root;
for(int i=0;i<len;i++){
o=Trie[o][s[i]-'a'];
int p=o;
while(p){
if((isend[p].size()))
for(int j=0;j<isend[p].size();j++)
if((inq-isend[p][j]+1)>=1&&(i+1-y+1>=1))
counts[inq-isend[p][j]+1][i+1-y+1]++;
p=fail[p];
}
}
}
void init(void){
memset(Trie,0,sizeof(Trie));
memset(fail,0,sizeof(fail));
memset(counts,0,sizeof(counts));
for(int i=0;i<=Nodecnt;i++)
isend[i].clear();
Nodecnt=0;
root=0;
}
int main(){
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
int T;
Nodecnt=0;
root=0;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",s[i]);
scanf("%d %d",&x,&y);
for(int i=1;i<=x;i++){
scanf("%s",t[i]);
insert(t[i],y,i);
}
build_AC();
for(int i=1;i<=n;i++){
query(s[i],m,i);
}
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(counts[i][j]==x)
ans++;
printf("%d\n",ans);
init();
}
return 0;
}