UVA

给你一个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
",ans);
38     }
39     return 0;
40 }
原文地址:https://www.cnblogs.com/asdfsag/p/10340421.html