题解:这里是二维网格的匹配,运用循环哈希,首先把每一行看成一个字符串,计算从每个位置开始长度为Q的字符串子串的哈希值。然后把得到的哈希值在列方向上看成一个字符串,计算每个位置开始长度为P的字符串子串的哈希值。这样,高效地计算得到了所有的P*Q的子阵的哈希值。在两次哈希值的计算中,选用不同的基数。
附上代码:
#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
const int MAX_SIZE=1e3+50;
const int MAX_T=150;
typedef unsigned long long ull;
int N,M,T,P,Q;
char field[MAX_SIZE][MAX_SIZE];
char patterns[MAX_T][MAX_SIZE][MAX_SIZE];
ull hashh[MAX_SIZE][MAX_SIZE],tmp[MAX_SIZE][MAX_SIZE];
void compute_hash(char a[MAX_SIZE][MAX_SIZE],int n,int m)
{
const ull B1=9973;
const ull B2=100000007;
ull t1=1;
for(int j=0;j<Q;j++){
t1*=B1;
}
for(int i=0;i<n;i++){
ull e=0;
for(int j=0;j<Q;j++){
e=e*B1+a[i][j];
}
for(int j=0;j+Q<=m;j++){
tmp[i][j]=e;
if(j+Q<m){
e=e*B1-t1*a[i][j]+a[i][j+Q];
}
}
}
ull t2=1;
for(int i=0;i<P;i++){
t2*=B2;
}
for(int j=0;j+Q<=m;j++){
ull e=0;
for(int i=0;i<P;i++){
e=e*B2+tmp[i][j];
}
for(int i=0;i+P<=n;i++){
hashh[i][j]=e;
if(i+P<n){
e=e*B2-t2*tmp[i][j]+tmp[i+P][j];
}
}
}
}
void solve()
{
multiset<ull>unseen;
for(int k=0;k<T;k++){
compute_hash(patterns[k],P,Q);
unseen.insert(hashh[0][0]);
}
compute_hash(field,N,M);
for(int i=0;i+P<=N;i++){
for(int j=0;j+Q<=M;j++){
unseen.erase(hashh[i][j]);
}
}
int ans=T-unseen.size();
printf("%d\n",ans);
}
int main()
{
int casen=1;
while(scanf("%d%d%d%d%d",&N,&M,&T,&P,&Q)!=EOF){
if(N==0&&M==0&&T==0&&P==0&&Q==0){
break;
}
getchar();
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
scanf("%c",&field[i][j]);
}
getchar();
}
for(int i=0;i<T;i++){
getchar();
for(int j=0;j<P;j++){
for(int k=0;k<Q;k++){
scanf("%c",&patterns[i][j][k]);
}
getchar();
}
}
printf("Case %d: ",casen++);
solve();
}
return 0;
}