字符串——二维矩阵Hash

字符串——二维矩阵Hash

本文介绍的是一种关于二维矩阵Hash的方法,用于在 O ( 1 ) O(1) O(1)的时间内求出子矩阵的Hash值。

NC 51003

构造

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=0c1A[r][ci]×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=0r1rhash[ri][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=0r1j=0c1B2i×B1j×A[ri][cj]

查询

构造之后就可以像二维前缀和一样查询了,对于左上角为 ( 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[r11][c2]×B2r2r1+1hash[r2][c11]×B1c2c1+1+hash[r11][c11]×B2r2r1+1×B1c2c1+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");
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值