字符串hash——Matrix(二维)
题目描述
给定一个M行N列的01矩阵(只包含数字0或1的矩阵),再执行Q次询问,每次询问给出一个A行B列的01矩阵,求该矩阵是否在原矩阵中出现过。
输入描述
第一行四个整数M,N,A,B。
接下来一个M行N列的01矩阵,数字之间没有空格。
接下来一个整数Q。
接下来Q个A行B列的01矩阵,数字之间没有空格。
输出描述
对于每个询问,输出1表示出现过,0表示没有。
示例
输入
3 3 2 2
111
000
111
3
11
00
11
11
00
11
输出
1
0
1
备注
对于40%的数据,A = 1。
对于80%的数据,A ≤ 10。
对于100%的数据,A ≤ 100,M,N ≤ 1000,Q ≤ 1000。
分析
这题是二维 hash,可以先看图中的蓝色矩形,假设其长为 a,宽为 b,右下角的点所在位置为 (i,j),其总的 hash 值为 S。
当其向下移动,即到了红色方框框起的位置,其 hash 值变为了 S * p[b] + h[i+1][j] - h[i+1][j-b] * p[b] - (h[i-a][j] - h[i-a][j-b] * p[b]) * p[a * b]。
h[i+1][j] - h[i+1][j-b] * p[b] 表示向下移动所新增的部分。
(h[i-a][j] - h[i-a][j-b] * p[b]) * p[a * b] 表示向下移动后不在框内的部分,如蓝色矩形最上面一行的部分。
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 1005,base=13331;
ULL p[N*N],h[N][N];
char s[N][N],c[N][N];
vector<unsigned long long> l;
int main()
{
int m,n,a,b;
scanf("%d%d%d%d",&m,&n,&a,&b);
p[0]=1;
for(int i=1;i<=n*m;i++){
p[i]=p[i-1]*base;
}
for(int i=1;i<=m;i++){
getchar();
for(int j=1;j<=n;j++){
scanf("%c",&s[i][j]);
h[i][j]=h[i][j-1]*base+s[i][j]-'0';
}
}
for(int i=b;i<=n;i++){
ULL tt=0;
for(int j=1;j<=m;j++){
tt=tt*p[b]+h[j][i]-h[j][i-b]*p[b];
if(j>a){
tt-=(h[j-a][i]-h[j-a][i-b]*p[b])*p[a*b];
}
if(j>=a){
l.push_back(tt);
}
}
}
sort(l.begin(),l.end());
int q;
scanf("%d",&q);
while(q--){
ULL hh=0;
for(int i=1;i<=a;i++){
getchar();
for(int j=1;j<=b;j++){
scanf("%c",&c[i][j]);
hh=hh*base+c[i][j]-'0';
}
}
if(lower_bound(l.begin(),l.end(),hh)!=l.end()&&*lower_bound(l.begin(),l.end(),hh)==hh){
printf("1\n");
}
else{
printf("0\n");
}
}
return 0;
}