第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem K. Bitmap-题解

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem K. Bitmap-题解相关的知识,希望对你有一定的参考价值。

传送门

Problem A. Mex Query

Problem B. Nim Game

Problem C. icebound 的账单

Problem G. 520

Problem H. 神殿

Problem J. icebound 的商店

Problem K. Bitmap

       哈希讲解
       二维哈希讲解

Problem L. 跑图





Problem K. Bitmap

Time Limit: 1000ms
Memory Limit: 262144KB

Description

RSYJ is a computer scientist. He has developed many useful image search tools. But now he has encountered some problems.

We use a matrix of H × H H \\times H H×H to represent a bitmap with H × H H \\times H H×H size, and each pixel of the 8 8 8-bit bitmap is represented by the integer between [ 0 , 255 ] [0,255] [0,255].

Now, RSYJ have a 8 8 8-bit bitmap A A A with n × n n \\times n n×n size, and a 8 8 8-bit bitmap B B B with m × m m \\times m m×m size.RSYJ uses an image processing software to copy bitmap B B B to some positions in bitmap A A A. Due to RSYJ’s computer’s error, the value of each pixel in the bitmap B B B is added with an offset k k k , which is an integer, but RSYJ doesn’t know what k k k is.

Now your task is writing a program to help RSYJ find all positions of bitmap B B B in the bitmap A A A. To simplify the problem, you only need output how many positions of bitmap B B B in bitmap A A A.

For example, here are two bitmaps A A A and B B B:

AB
10 9 3
11 6 5
15 7 2
4 3
5 0

Bitmap B B B was added with an offset: 6 6 6. It becomes:

10 9

11 6

Bitmap B B B was added with an offset: 2 2 2. It becomes:

6 5

7 2

So there are two positions of bitmap B B B in bitmap A A A.

Input

The first line of the input gives two positive integers n , m n , m n,m, representing the size of bitmap A A A and the size of bitmap B B B, respectively.

The next nn lines give the bitmap A A A . Each line contains nn integers.

The next mm lines give the bitmap B B B . Each line contains mm integers.

1 ≤ n ≤ 400 1 \\leq n \\leq 400 1n400,

1 ≤ m ≤ 200 1 \\leq m \\leq 200 1m200,

0 ≤ a i j ≤ 255 0 \\leq a_{ij} \\leq 255 0aij255,

0 ≤ b i j ≤ 255 0 \\leq b_{ij} \\leq 255 0bij255

Output

Please output an integer, representing the number of positions of bitmap B B B in bitmap A A A.

Sample Input

3 2
1 2 9
3 4 7
5 6 0
3 4
5 6

Sample Output

2

题目大意

给你两个矩阵,一个是大矩阵,一个是小矩阵。
矩阵中值的范围必须是0 ~ 255,你把小矩阵中的每个值都加上或减去一个相同的数(还要保证每个数范围都是0 ~ 255),看看能不能在大矩阵中找到小矩阵。
尝试给小矩阵加上所有可以加的数,看看能在大矩阵中找到多少小矩阵。


解题思路

这是一道二维哈希题。
如果您还不会哈希,请先到这里 → \\rightarrow 哈希
如果您还不会二维哈希,请再到这里 → \\rightarrow 二维哈希

好了,请允许我认为你已经会了(二维)哈希 ( q w q qwq qwq)。

那么这一题,在给出矩阵A后,我们就可以求出A中所有的大小为B的子矩阵的哈希值,并记录下来(下标过大,可以使用map来记录)。
之后计算出矩阵B的哈希值,同时记录下来B的最大值和最小值,以便确定B的偏移量的范围。
如果每次都真的把B中的每一个数都加上一个偏移量,再重新计算B的哈希,那么复杂度是 O ( 255 × m 2 ) O(255\\times m^2) O(255×m2),此题可以通过。
但是我们想到哈希的意义,可以理解为 b a s e base base进制下的数。我们先拿大家最熟悉的 10 10 10进制来举例:

假如矩阵B是 5   7   4   2 5\\ 7\\ 4\\ 2 5 7 4 2,那么十进制下矩阵B的哈希就是 5742 5742 5742
把B中的每一个元素 + 1 +1 +1 6853 6 8 5 3 6853,那么哈希值为 6853 6853 6853
再加一得 7964 7964 7964
不难发现 7964 − 6853 = 1111 , 6853 − 5742 = 1111 7964-6853=1111,6853-5742=1111 79646853=1111,68535742=1111。因此我们知道原来矩阵B的哈希值 5742 5742 5742后,就不需要每次都把B中的每个元素 + 1 +1 +1,只需要每次把B的哈希值 + 1111 +1111 +1111即可。
那么 1111 1111 1111是怎么来的呢? 1111 = 1 + 1 ∗ 10 + 1 ∗ 10 ∗ 10 + 1 ∗ 10 ∗ 10 ∗ 10 1111=1+1*10+1*10*10+1*10*10*10 1111=1+110+11010+1101010,其中 10 10 10 10 10 10进制。

那么换成 p p p进制的话,我们可以先算出来那个“1111”(记为 o n c e once once),方法是: o n c e = ∑ i = 0 m ∗ m p i once=\\sum_{i=0}^{m*m}p^i once=i=0mmpi
因此,我们得到B的初始的哈希后,只需要每次都加上或减去 o n c e once once即可。


另外,这题在 p = 131 p=131 p=131 u n s i g n e d   l o n g   l o n g unsigned\\ long\\ long unsigned long long自然溢出即可通过。

emmm,如果还不太懂,代码还有一些注释:

AC代码

#include<bits/stdc++.h>
#include<map>
using namespace std;
typedef unsigned long long ull;
const int N=400;//矩阵A的范围
const int M=200;//矩阵B的范围
const int p=131;//131进制
ull power[M*N+5];//power[i]代表p的i次方
ull A[N+5][N+5];//矩阵A的行哈希
ull getLine(int x,int l,int r)//第i行从l到r的哈希
{
    return A[x][r]-A[x][l-1]*power[r-l+1];
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)//涉及到前缀的一般从1开始
    {
        A[i][0]=0;
        for(int j=1;j<=n;j++)
        {
            int t;
            scanf("%d",&t);
            A[i][j]=A[i][j-1]*p+t;//这个数的行哈希=左边的行哈希*进制+这个数
        }
    }
    power[0]=1;//131^0=1
    for(int i=1;i<=m*m;i++)//最多用到131^(m*m)
    {
        power[i]=power[i-1]*p;//不用取模,自然溢出即可(对2^64取模)
    }
    map<ull,int>Map;//用来记录A中一个大小为B的矩阵的哈希出现过哪几次
    for(int i=m;i<=n;i++)//先求列
    {
        ull s=0;//初始值是0
        int r=i,l=r-m+1;//从l到r
        for(int j=1;j<=n;j++)
        {
            s=s*power[m]+getLine(j,l,r);//上一行l~r的行哈希*p^m加上这一行l~r的行哈希
            if(j>m)s=s-getLine(j-m,l,r)*power[m*m];//如果这是第m+1行及更大,就需要减去多余B矩阵的那一行
            if(j>=m)Map[s]++;//如果这个矩阵的范围已经达到了B矩阵的范围,记录下来
        }
    }
    //B:
    ull s=0;//B矩阵的初始哈希
    int mb=256,Mb=0;//B矩阵中的最小值(初始值为256)、最大值(初始值为0)
    for(int i=1;i<=m;i++

以上是关于第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem K. Bitmap-题解的主要内容,如果未能解决你的问题,请参考以下文章

第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem G. 520-题解

第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem K. Bitmap-题解

第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem C. icebound 的账单-题解

第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem J. icebound 的商店-题解

第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem B. Nim Game-题解

第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem A. Mex Query-题解