题目链接
题解
这道题一看就知道是个二维hash,然而蒟蒻我并不会,于是想了另外一种水法:KMP。
首先对小矩阵的每一列压位变成一个long long。然后小矩阵就变成了一个长度为q的数组。对大矩阵做同样的操作,每列p位压成一个数(可重叠),然后大矩阵就变成了n-p+1行m列的矩阵。
对矩阵的每一行与数组做KMP即可。
时间复杂度O(跑得过)。
ps:数据好水,刚AC的程序被我hack掉了。。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstdlib>
#define maxn 1010
using namespace std;
typedef long long LL;
int n, m, p, q, T, ans, Case;
char M1[maxn][maxn], M2[maxn][maxn];
LL D1[maxn][maxn], D2[maxn];
int nxt[maxn];
bool KMP(int x){
nxt[0] = nxt[1] = 0;
int k = 0;
for(int i = 2; i <= q; i++){
while(k && D2[k] != D2[i-1]) k = nxt[k];
if(D2[k] == D2[i-1]) k ++;
nxt[i] = k;
}
k = 0;
for(int i = 1; i <= m; i++){
while(k && D2[k] != D1[x][i-1]) k = nxt[k];
if(D2[k] == D1[x][i-1]) k ++;
if(k == q) return true;
}
return false;
}
int main(){
for(;;){
scanf("%d%d%d%d%d", &n, &m, &T, &p, &q);
if(!n && !m && !T && !p && !q) break;
ans = 0;
for(int i = 1; i <= n; i++)
scanf("%s", M1[i]);
for(int j = 0; j < m; j++){
D1[1][j] = 0LL;
for(int i = 1, t = 0; i <= p; i++, t++)
if(M1[i][j] == '*') D1[1][j] += (1LL << t);
for(int i = p+1; i <= n; i++){
D1[i-p+1][j] = (D1[i-p][j] >> 1LL);
if(M1[i][j] == '*') D1[i-p+1][j] += (1LL << (p-1));
}
}
while(T --){
for(int i = 1; i <= p; i++)
scanf("%s", M2[i]);
for(int j = 0; j < q; j++){
D2[j] = 0LL;
for(int i = 1, t = 0; i <= p; i++, t++)
if(M2[i][j] == '*') D2[j] += (1LL << t);
}
for(int i = 1; i <= n-p+1; i++)
if(KMP(i)){
ans ++;
break;
}
}
printf("Case %d: %d\n", ++Case, ans);
}
return 0;
}
我对命运嗤之以鼻,命运赐我以葬礼。