二维的矩阵匹配,把模式矩阵按列拆开构造AC自动机,记录行号(为了缩点判断)。
把T矩阵按行匹配,一旦匹配成功,在假想的子矩阵左上角位置加一。最后统计总数。
因为所有模式串长度一样,不用维护last数组。
模式串可能有重复,结点要用vector来存。
HASH出奇迹,快得不行。。。
#include<bits/stdc++.h> using namespace std; const int maxn = 1001,maxm = 101; char Text[maxn][maxn], pattern[maxm]; const int maxnds = maxm*maxm, sigma_size = 26; int nds; int ch[maxnds][sigma_size]; int f[maxnds]; vector<int> val[maxnds]; void bfs() { f[0] = 0; queue<int> q; for(int c = 0; c < sigma_size; c++){ int u = ch[0][c]; if(u){ q.push(u); f[u] = 0;} } while(q.size()){ int r = q.front(); q.pop(); for(int c = 0; c < sigma_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]; } } } #define idx(x) x-'a'; void add(char *s,int i) { int n = strlen(s), u = 0; for(int i = 0; i < n; i++){ int c = idx(s[i]); if(!ch[u][c]){ u = ch[u][c] = nds++; memset(ch[u],0,sizeof(ch[u])); val[u].clear(); }else u = ch[u][c]; } val[u].push_back(i); } void init() { nds = 1; memset(ch[0],0,sizeof(ch[0])); val[0].clear(); } int cnt[maxn][maxn]; int N,M; int X,Y; void cal(int i,int j) { if(i>=0) cnt[i][j]++; } void Find(char *T,int R) { int n = strlen(T), u = 0; for(int i = 0; i < n; i++){ int c = idx(T[i]); u = ch[u][c]; if(val[u].size() ){ for(auto it:val[u]){ cal(R-it+1,i-Y+1); } } } } int main() { //freopen("in.txt","r",stdin); int T;cin>>T; while(T--){ init(); scanf("%d%d",&N,&M); for(int i = 0; i < N; i++){ scanf("%s",Text[i]); } scanf("%d%d",&X,&Y); for(int i = 1; i <= X; i++){ scanf("%s",pattern); add(pattern,i); } bfs(); for(int i = 0; i < N; i++){ Find(Text[i],i); } int ans = 0; for(int i = 0; i < N; i++){ for(int j = 0; j < M; j++){ if(cnt[i][j]){ if(cnt[i][j] == X) ans++; cnt[i][j] = 0; } } } printf("%d ",ans); } return 0; }