字符串——二维矩阵Hash
本文介绍的是一种关于二维矩阵Hash的方法,用于在 O ( 1 ) O(1) O(1)的时间内求出子矩阵的Hash值。
构造
for (int r = 1; r <= n; r++)
for (int c = 1; c <= m; c++)
m_hash[r][c] = (m_hash[r][c - 1] * HASH_BASE % HASH_MOD + matrix[r][c]) % HASH_MOD;
首先对行取多项式,即:
r h a s h [ r ] [ c ] = ∑ i = 0 c − 1 A [ r ] [ c − i ] × B 1 i rhash[r][c] = \sum_{i = 0}^{c-1} A[r][c-i] \times B_1^{i} rhash[r][c]=i=0∑c−1A[r][c−i]×B1i
然后对列取多项式,即:
h a s h [ r ] [ c ] = ∑ i = 0 r − 1 rhash [ r − i ] [ c ] × B 2 i hash[r][c] = \sum_{i = 0}^{r-1} \text{rhash}[r-i][c] \times B_2^{i} hash[r][c]=i=0∑r−1rhash[r−i][c]×B2i
最终得到一个由二维多项式值构成的二维Hash:
h a s h [ r ] [ c ] = ∑ i = 0 r − 1 ∑ j = 0 c − 1 B 2 i × B 1 j × A [ r − i ] [ c − j ] hash[r][c] = \sum_{i = 0}^{r - 1} \sum_{j = 0}^{c - 1} B_2^{i} \times B_1^{j} \times A[r - i][c - j] hash[r][c]=i=0∑r−1j=0∑c−1B2i×B1j×A[r−i][c−j]
查询
构造之后就可以像二维前缀和一样查询了,对于左上角为 ( r 1 , c 1 ) (r_1,c_1) (r1,c1)右下角为 ( r 2 , c 2 ) (r_2,c_2) (r2,c2)的子矩阵来说,它的Hash值为:
H a s h = h a s h [ r 2 ] [ c 2 ] − h a s h [ r 1 − 1 ] [ c 2 ] × B 2 r 2 − r 1 + 1 − h a s h [ r 2 ] [ c 1 − 1 ] × B 1 c 2 − c 1 + 1 + h a s h [ r 1 − 1 ] [ c 1 − 1 ] × B 2 r 2 − r 1 + 1 × B 1 c 2 − c 1 + 1 Hash = hash[r_2][c_2] - hash[r_1 - 1][c_2] \times B_2^{r_2 - r_1 + 1} - hash[r_2][c_1 - 1] \times B_1^{c_2 - c_1 + 1} + hash[r_1 - 1][c_1 - 1] \times B_2^{r_2 - r_1 + 1} \times B_1^{c_2 - c_1 + 1} Hash=hash[r2][c2]−hash[r1−1][c2]×B2r2−r1+1−hash[r2][c1−1]×B1c2−c1+1+hash[r1−1][c1−1]×B2r2−r1+1×B1c2−c1+1
模板
const ll HASH_BASE = 25165843;
const ll HASH_BASE_2 = 4564988929;
char matrix[1005][1005];
ll m_hash[1005][1005];
ll bit_1[1005];
ll bit_2[1005];
void solve()
{
bit_1[0] = bit_2[0] = 1;
for (int i = 1; i < 1005; i++)
{
bit_1[i] = bit_1[i - 1] * HASH_BASE;
bit_2[i] = bit_2[i - 1] * HASH_BASE_2;
}
int n, m, a, b;
scanf("%d %d %d %d", &n, &m, &a, &b);
for (int r = 1; r <= n; r++)
scanf("%s", matrix[r] + 1);
for (int r = 1; r <= n; r++)
for (int c = 1; c <= m; c++)
m_hash[r][c] = m_hash[r][c - 1] * HASH_BASE + matrix[r][c];
for (int r = 1; r <= n; r++)
for (int c = 1; c <= m; c++)
m_hash[r][c] = m_hash[r - 1][c] * HASH_BASE_2 + m_hash[r][c];
auto h = [](int r1, int c1, int r2, int c2)
{
ll val = m_hash[r2][c2];
val = val - m_hash[r1 - 1][c2] * bit_2[r2 - r1 + 1];
val = val - m_hash[r2][c1 - 1] * bit_1[c2 - c1 + 1];
val = val + m_hash[r1 - 1][c1 - 1] * bit_1[c2 - c1 + 1] * bit_2[r2 - r1 + 1];
return val;
};
vector<ll> vec;
for (int r = 1; r + a - 1 <= n; r++)
for (int c = 1; c + b - 1 <= m; c++)
{
ll val = h(r, c, r + a - 1, c + b - 1);
vec.push_back(val);
}
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
int T;
scanf("%d", &T);
while (T--)
{
for (int r = 1; r <= a; r++)
scanf("%s", matrix[r] + 1);
for (int r = 1; r <= a; r++)
for (int c = 1; c <= b; c++)
m_hash[r][c] = m_hash[r][c - 1] * HASH_BASE + matrix[r][c];
for (int r = 1; r <= a; r++)
for (int c = 1; c <= b; c++)
m_hash[r][c] = m_hash[r - 1][c] * HASH_BASE_2 + m_hash[r][c];
ll val = m_hash[a][b];
auto it = lower_bound(vec.begin(), vec.end(), val);
if (it == vec.end() || *it != val)
printf("0\n");
else
printf("1\n");
}
}