Problem H
Matrix Matcher
Input: Standard Input
Output: Standard Output
Given an N * M matrix, your task is to find the number of occurences of an X * Y pattern.
Input
The first line contains a single integer t(t ≤ 15), the number of test cases.
For each case, the first line contains two integers N and M (N, M ≤ 1000). The next N lines contain M characters each.
The next line contains two integers X and Y (X, Y ≤ 100). The next X lines contain Y characters each.
Output
For each case, output a single integer in its own line, the number of occurrences.
Sample Input Output for Sample Input
2 1 1 x 1 1 y 3 3 abc bcd cde 2 2 bc cd | 0 2
|
Problem Setter: Rujia Liu, EPS
Special Thanks: Wenbin Tang
Warming: The judge input file size is about 7 MB. So please make sure that you use a fast IO function (eg. scanf()) to read input.
题目地址:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1960
说白了,判断一个子矩阵在母矩阵中出现的次数,怎么办?
矩阵中的元素是字母,字母是在'a'-'z'之间的
暴力扫不现实,用AC自动机来做。先把子矩阵的每一行当作一个模版串,构成AC自动机
然后把母矩阵的每一行当作文本串,放到自动机里去扫。
边扫边构成一个新的矩阵。新矩阵的定义是 i,j 这个位置在母矩阵中,如果是一个模版串的尾字母,那就存储这个尾字母对应的节点编号。否则存储0.
在之前构建自动机的时候,可以记录每一行它尾字母对应的节点的编号,这就构成一个新的模版串
而新的矩阵的每一列又可以看做一个新的文本串
这样,对新的模版串和m个新的文本串跑m发kmp.. 就可以求出子矩阵在母矩阵出现的次数了。
其实,AC自动机是必要的,再用上kmp是我自己想出来的。相信还有别的方法算出子矩阵在母矩阵中出现的次数。不管怎样,我就我的傻逼方法了
这题很好,算是一道综合题吧。I like it.
//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define pb(a) push_back(a)
#define clr(a) memset(a,0,sizeof(a))
#define clr_minus1(a) memset(a,-1,sizeof(a))
#define clr_INT(a) memset(a,INT,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_false(a) memset(a,false,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define pi 3.1415926535898
#define eps 1e-6
#define MOD 1000000007
#define MAXN 1024
#define N 300100
#define M 26
char matrix[MAXN][MAXN];
char word[200];
int belong[200];
int n,m,x,y;
int num_node,trie[N][M],val[N];
int idx(char c){
return c-'a';
}
void init_trie()
{
clr(trie[0]);
num_node=1;
}
void plant_trie(char *s,int len,int number)
{
int now=0,letter;
rep(i,0,len)
{
letter=idx(s[i]);
if(!trie[now][letter])
{
trie[now][letter]=num_node;
val[num_node]=0;
clr(trie[num_node]);
num_node+=1;
}
now=trie[now][letter];
}
val[now]=number;
belong[number-1]=now;
}
int nextpos[N],lastpos[N];
queue<int>q;
void Build_nextlastpos()
{
clr_queue(q);
nextpos[0]=lastpos[0]=0;
int now;
rep(i,0,M)
{
now=trie[0][i];
if(now)
{
nextpos[now]=0;
lastpos[now]=0;
q.push(now);
}
}
int son,nextone;
while(!q.empty())
{
now=q.front();
q.pop();
rep(i,0,M)
{
son=trie[now][i];
nextone=nextpos[now];
if(!son)
{
trie[now][i]=trie[nextone][i];//AC自动机优化
continue;
}
while(nextone && !trie[nextone][i]) nextone=nextpos[nextone];//AC自动机优化
nextpos[son]=trie[nextone][i];
lastpos[son]=val[nextpos[son]]?nextpos[son]:lastpos[nextpos[son]];
q.push(son);
}
}
}
int newmatrix[MAXN][MAXN];
void print(int row,int col,int pos)
{
if(pos)
{
newmatrix[row-1][col-1]=pos;
print(row,col,lastpos[pos]);
}
}
void Aho_Corasick_search(int row,char *s,int len)
{
int now=0,letter;
repin(i,1,len)
{
letter=idx(s[i]);
now=trie[now][letter];
if(val[now]) print(row,i,now);
else if(lastpos[now]) print(row,i,lastpos[now]);
}
}
//上面是AC自动机
//下面是KMP
int kmpnext[MAXN];
void Build_kmpnext()
{
int i,j;
i=0;
kmpnext[0]=j=-1;
while(i<x)
{
if(j==-1 || belong[i]==belong[j])
{
kmpnext[i+1]=j+1;
if(belong[j+1]==belong[i+1]) kmpnext[i+1]=kmpnext[j+1];//kmp优化
i++;
j=j+1;
}
else j=kmpnext[j];
}
}
ll ans;
void kmp_search(int col)
{
int i,j;
i=j=0;
while(i<n)
{
if(j==-1 || newmatrix[i][col]==belong[j])
{
i++;
j++;
}
else j=kmpnext[j];
if(j==x)
{
ans+=1;
j=kmpnext[j];
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d %d",&n,&m);
repin(i,1,n)
{
repin(j,1,m)
{
newmatrix[i][j]=0;
}
scanf("%s",matrix[i]+1);
}
init_trie();
scanf("%d %d",&x,&y);
repin(i,1,x)
{
scanf("%s",word);
plant_trie(word,y,i);
}
Build_nextlastpos();
repin(i,1,n)
{
Aho_Corasick_search(i,matrix[i],m);
}
Build_kmpnext();
ans=0;
repin(j,1,m)
{
kmp_search(j);
}
printf("%lld\n",ans);
}
}