二维哈希-矩阵
一维哈希:
在
一
维
哈
希
中
,
我
们
是
将
长
度
长
度
为
n
的
序
列
哈
希
成
长
度
为
n
的
一
个
P
进
制
数
,
高
位
在
前
。
在一维哈希中,我们是将长度长度为n的序列哈希成长度为n的一个P进制数,高位在前。
在一维哈希中,我们是将长度长度为n的序列哈希成长度为n的一个P进制数,高位在前。
二位哈希:
在
二
维
哈
希
中
,
就
是
将
n
×
m
的
序
列
哈
希
成
一
个
长
度
为
n
×
m
的
P
进
制
数
,
依
然
是
高
位
在
前
。
在二维哈希中,就是将n×m的序列哈希成一个长度为n×m的P进制数,依然是高位在前。
在二维哈希中,就是将n×m的序列哈希成一个长度为n×m的P进制数,依然是高位在前。
处理过程:
① 、 行 哈 希 : 首 先 对 矩 阵 的 每 一 行 的 m 个 元 素 分 别 进 行 一 维 哈 希 。 ①、行哈希:首先对矩阵的每一行的m个元素分别进行一维哈希。 ①、行哈希:首先对矩阵的每一行的m个元素分别进行一维哈希。
② 、 列 哈 希 : 接 着 可 以 将 矩 阵 的 每 一 行 视 作 一 位 , 从 上 到 下 视 作 一 个 n 个 元 素 的 序 列 , 类 比 一 维 哈 希 。 ②、列哈希:接着可以将矩阵的每一行视作一位,从上到下视作一个n个元素的序列,类比一维哈希。 ②、列哈希:接着可以将矩阵的每一行视作一位,从上到下视作一个n个元素的序列,类比一维哈希。
公式推导:
求大小为a×b的子矩阵的哈希值
① 、 首 先 预 处 理 整 个 n × m 的 矩 阵 每 一 行 的 哈 希 值 。 ①、首先预处理整个n×m的矩阵每一行的哈希值。 ①、首先预处理整个n×m的矩阵每一行的哈希值。
设 第 i 行 第 j 列 的 元 素 为 a [ i ] [ j ] , 1 < = i < = n , 1 < = j < = m , 设第i行第j列的元素为a[i][j],1<=i<=n,1<=j<=m, 设第i行第j列的元素为a[i][j],1<=i<=n,1<=j<=m,
则 第 i 行 前 j 个 元 素 的 哈 希 值 h [ i ] [ j ] = h [ i ] [ j − 1 ] × P + a [ i ] [ j ] 。 则第i行前j个元素的哈希值h[i][j]=h[i][j-1]×P+a[i][j]。 则第i行前j个元素的哈希值h[i][j]=h[i][j−1]×P+a[i][j]。
②
、
再
求
a
×
b
的
矩
阵
的
哈
希
值
。
②、再求a×b的矩阵的哈希值。
②、再求a×b的矩阵的哈希值。
设
右
下
角
坐
标
为
(
i
,
j
)
的
a
×
b
的
矩
阵
的
哈
希
值
为
H
[
i
]
[
j
]
,
矩
阵
每
一
行
的
b
个
元
素
的
哈
希
值
可
以
由
一
维
哈
希
的
方
法
求
出
为
h
[
k
]
[
j
−
b
+
1
,
j
]
,
k
∈
[
i
−
a
+
1
,
i
]
。
设右下角坐标为(i,j)的a×b的矩阵的哈希值为H[i][j],\\矩阵每一行的b个元素的哈希值可以由一维哈希的方法求出为h[k][j-b+1,j],k∈[i-a+1,i]。
设右下角坐标为(i,j)的a×b的矩阵的哈希值为H[i][j],矩阵每一行的b个元素的哈希值可以由一维哈希的方法求出为h[k][j−b+1,j],k∈[i−a+1,i]。
则
其
对
应
的
第
i
+
1
行
的
的
a
×
b
的
矩
阵
的
哈
希
值
H
[
i
+
1
]
[
j
]
可
以
由
该
矩
阵
的
所
有
元
素
向
高
位
移
动
b
位
,
再
加
上
第
i
+
1
行
的
哈
希
值
,
然
后
减
去
第
i
个
矩
阵
的
第
一
行
的
哈
希
值
得
到
。
则其对应的第i+1行的的a×b的矩阵的哈希值H[i+1][j]可以由该矩阵的所有元素向高位移动b位,\\再加上第i+1行的哈希值,然后减去第i个矩阵的第一行的哈希值得到。
则其对应的第i+1行的的a×b的矩阵的哈希值H[i+1][j]可以由该矩阵的所有元素向高位移动b位,再加上第i+1行的哈希值,然后减去第i个矩阵的第一行的哈希值得到。
即 : H [ i + 1 ] [ j ] = H [ i ] [ j ] × P b + h [ i + 1 ] [ j − b + 1 , j ] − h [ ( i + 1 ) − a ] [ j − b + 1 , j ] × P a b 。 要 注 意 , 第 i + 1 − a 行 的 元 素 要 比 第 i + 1 行 元 素 对 应 的 高 a × b 位 , 因 此 最 后 减 的 时 候 要 乘 上 。 即:H[i+1][j]=H[i][j]×P^b+h[i+1][j-b+1,j]-h[(i+1)-a][j-b+1,j]×P^{ab}。\\要注意,第i+1-a行的元素要比第i+1行元素对应的高a×b位,因此最后减的时候要乘上。 即:H[i+1][j]=H[i][j]×Pb+h[i+1][j−b+1,j]−h[(i+1)−a][j−b+1,j]×Pab。要注意,第i+1−a行的元素要比第i+1行元素对应的高a×b位,因此最后减的时候要乘上。
题目:
给定一个M行N列的01矩阵(只包含数字0或1的矩阵),再执行Q次询问,每次询问给出一个A行B列的01矩阵,求该矩阵是否在原矩阵中出现过。
输入描述:
第一行四个整数M,N,A,B。
接下来一个M行N列的01矩阵,数字之间没有空格。
接下来一个整数Q。
接下来Q个A行B列的01矩阵,数字之间没有空格。
输出描述:
对于每个询问,输出1表示出现过,0表示没有。
示例1:
输入
3 3 2 2
111
000
111
3
11
00
11
11
00
11
输出
1
0
1
数据范围:
A
≤
100
,
M
,
N
≤
1000
,
Q
≤
1000
。
A≤100,M,N≤1000,Q≤1000。
A≤100,M,N≤1000,Q≤1000。
具体落实:
① 、 预 处 理 分 别 计 算 每 一 行 的 哈 希 值 。 ② 、 根 据 递 推 关 系 计 算 n × m 的 矩 阵 中 , 所 有 a × b 的 子 矩 阵 的 哈 希 值 并 存 入 哈 希 表 中 。 ③ 、 计 算 输 入 的 子 矩 阵 的 哈 希 值 再 查 询 哈 希 表 。 ①、预处理分别计算每一行的哈希值。\\②、根据递推关系计算n×m的矩阵中,所有a×b的子矩阵的哈希值并存入哈希表中。\\③、计算输入的子矩阵的哈希值再查询哈希表。 ①、预处理分别计算每一行的哈希值。②、根据递推关系计算n×m的矩阵中,所有a×b的子矩阵的哈希值并存入哈希表中。③、计算输入的子矩阵的哈希值再查询哈希表。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_set>
#define ull unsigned long long
using namespace std;
const int N=1010;
const int base=131;
int n,m,a,b;
ull h[N][N],p[N*N];
char str[N];
ull get(ull h[],int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
scanf("%d%d%d%d",&n,&m,&a,&b);
for(int i=1;i<=n;i++)
{
scanf("%s",str+1);
///单独求每一行的哈希值
for(int j=1;j<=m;j++)
h[i][j]=h[i][j-1]*base+str[j]-'0';
}
p[0]=1;
for(int i=1;i<=a*b;i++) p[i]=p[i-1]*base;
unordered_set<ull> S;
///j枚举右端点,求所有a×b的子矩阵哈希值
for(int j=b;j<=m;j++)
{
ull s=0;
int l=j-b+1,r=j;
for(int i=1;i<=n;i++) ///按列求哈希
{
s=s*p[b]+get(h[i],l,r);
if(i-a>0) s-=get(h[i-a],l,r)*p[a*b];
if(i-a>=0) S.insert(s);
}
}
int q;
scanf("%d",&q);
while(q--)
{
///计算输入的子矩阵的值
ull s=0;
for(int i=1;i<=a;i++)
{
scanf("%s",str+1);
for(int j=1;j<=b;j++)
s=s*base+str[j]-'0';
}
if(S.count(s)) puts("1");
else puts("0");
}
return 0;
}