UVA - 11019 Matrix Matcher (二维字符串哈希)
给你一个n*m的矩阵,和一个x*y的模式矩阵,求模式矩阵在原矩阵中的出现次数。
看上去是kmp在二维情况下的版本,但单纯的kmp已经无法做到了,所以考虑字符串哈希。
类比一维情况下的哈希算法,利用容斥可以得到二维情况下的哈希算法,同样可以做到O(1)的查询。总复杂度O(n*m+x*y)。
蓝书上给的AC自动机的算法复杂度似乎有误,当每行的字符串重复次数过多时复杂度可达O(n*m*x),被hash完爆。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef unsigned long long ll; 5 const int N=1000+10; 6 const ll pp1=19260817,pp2=233; 7 char s[N][N],s2[N][N]; 8 int n,m,n2,m2; 9 ll h[N][N],h2[N][N],p1[N*N],p2[N*N]; 10 11 void gethash(char s[][N],ll h[][N],int n,int m) { 12 for(int i=0; i<n; ++i) 13 for(int j=0; j<m; ++j) 14 h[i+1][j+1]=h[i][j+1]*pp1+h[i+1][j]*pp2-h[i][j]*pp1*pp2+s[i][j]; 15 16 } 17 18 ll Hash(ll h[][N],int x1,int y1,int x2,int y2) 19 {return h[x2+1][y2+1]-h[x1][y2+1]*p1[x2-x1+1]-h[x2+1][y1]*p2[y2-y1+1]+h[x1][y1]*p1[x2-x1+1]*p2[y2-y1+1];} 20 21 int main() { 22 p1[0]=p2[0]=1; 23 for(int i=1; i<N*N; ++i)p1[i]=p1[i-1]*pp1,p2[i]=p2[i-1]*pp2; 24 int T; 25 scanf("%d",&T); 26 while(T--) { 27 scanf("%d%d",&n,&m); 28 for(int i=0; i<n; ++i)scanf("%s",s[i]); 29 gethash(s,h,n,m); 30 scanf("%d%d",&n2,&m2); 31 for(int i=0; i<n2; ++i)scanf("%s",s2[i]); 32 gethash(s2,h2,n2,m2); 33 int ans=0; 34 for(int i=0; i<n; ++i)if(i+n2-1<n) 35 for(int j=0; j<m; ++j)if(j+m2-1<m) 36 if(Hash(h,i,j,i+n2-1,j+m2-1)==h2[n2][m2])ans++; 37 printf("%d\n",ans); 38 } 39 return 0; 40 }