BZOJ2351Matrix (矩阵) 二维哈希

 

 

给定一个M行N列的01矩阵(只包含数字0或1的矩阵),再执行Q次询问,每次询问给出一个A行B列的01矩阵,求该矩阵是否在原矩阵中出现过。

输入格式

第一行四个整数M,N,A,B。

接下来一个M行N列的01矩阵,数字之间没有空格。

接下来一个整数Q。

接下来Q个A行B列的01矩阵,数字之间没有空格。

输出格式

对于每个询问,输出1表示出现过,0表示没有出现过。

数据范围

A≤100A≤100,M,N,B≤1000M,N,B≤1000,Q≤1000Q≤1000

输入样例:

3 3 2 2
111
000
111
3
11
00
11
11
00
11

输出样例:

1
0
1

 

这是二维的字符串的Hash,一维的字符串Hash具体原理:https://blog.csdn.net/sdz20172133/article/details/98859255

我们知道单行的任意子串的hash如何求了,如何扩展的二维的,怎么求一个大矩阵任意A*B的子矩阵的Hash呢,其实也是差不多的。如图,

BZOJ2351Matrix (矩阵) 二维哈希_第1张图片

0,1,2,3,4,5我们表示对其的p进制上的第几位。

我们假设已经求出S为矩阵A*B的Hash,那我们如何计算蓝色矩阵的Hash,先给出公式:

                                                  S*P^B+h[A+1][l~r]-h[1][l~r]*p^(A*B)

   h[A+1][l~r]存储A+1行字符串区间[l,r]子串的哈希值,[l,r]相当于[1,B]

 解释: S*P^B相当于把其往高位移动了一位(每一个位置相当于提高了两位),然后加上个位h[A+1][l~r],然后减去第一行的

h[1][l~r]*p^(A*B)。

//核心思想:将字符串看成P进制数,P的经验值是131或13331,取这两个值的冲突概率低
//小技巧:取模的数用2^64,这样直接用unsigned long long存储,溢出的结果就是取模的结果
//如果超时改为unsigned int
#include
using namespace std;
typedef unsigned long long ULL;
const int N=1e3+5;
ULL hashv[N][N], power[N*N]; // hashv[k]存储字符串前k个字母的哈希值, power[k]存储 P^k mod 2^64
char str[N][N],str1[N];
int n,m,A,B;
int P;
// 初始化
void calHash()
{
    P=131;
   
    for (int i = 1; i <= n; i++ )
    {
        for(int j=1; j <= m; j++)
        {
            hashv[i][j] = hashv[i][j-1] * P + (str[i][j]-'0');
        }
    }
    
	power[0] = 1;
    for(int i=1; i<=n*m; i++)
    {
        power[i] = power[i - 1] * P;
    }
}
// 计算子串 str[l ~ r] 的哈希值
ULL get(ULL f[],int l, int r)
{
    return f[r] - f[l - 1] * power[r - l + 1];
}

int main()
{

    scanf("%d%d%d%d",&n,&m,&A,&B);
    for(int i=1; i<=n; i++)
    {
        scanf("%s",str[i]+1);
    }

    calHash();
    //将大小为A*B的矩阵Hash保存到Hash中
    unordered_set Hash;
    for(int i=B; i<=m; i++)
    {
        ULL s=0;
        int l=i-B+1,r=i;
        for(int j=1; j<=n; j++)
        {
            s=s*power[B]+get(hashv[j],l,r);
            if(j-A>0)
                s-=get(hashv[j-A],l,r)*power[A*B];
            if(j>=A)
                Hash.insert(s);
        }

    }

    int Q;
    scanf("%d",&Q);
    while(Q--)
    {
        ULL s=0;
        for(int i=1; i<=A; i++)
        {
            scanf("%s",str1+1);
            for(int j=1; j<=B; j++)
            {
                s=s*P+str1[j]-'0';
            }
        }
        if(Hash.count(s))
            printf("1\n");
        else
            printf("0\n");
    }



    return 0;
}

 

你可能感兴趣的:(模板,好题,字符串——字符串hash,数据结构——hash)