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

2024-04-11 11:08

本文主要是介绍第 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=1for(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;//初始值是0int r=i,l=r-m+1;//从l到rfor(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++){for(int j=1;j<=m;j++){int t;scanf("%d",&t);//输入B矩阵mb=min(mb,t);//更新最小值Mb=max(Mb,t);//和最大值s=s*p+t;//哈希=前面的哈希*p+这个数}}ull once=0;//B中的所有元素都变化1时,B矩阵总的哈希值的变化for(int i=0;i<m*m;i++){once+=power[i];}int Jian=mb,Jia=255-Mb;//要减去的次数、要加上的次数int ans=0;//答案ull tempS=s;//拷贝一份B矩阵的原始哈希for(int i=1;i<Jian;i++)//这次从1开始,没有计算原始B矩阵的哈希{tempS-=once;//每次-onceans+=Map[tempS];}tempS=s;//再拷贝一份for(int i=0;i<=Jia;i++)//这次从0开始,计算了B矩阵的原始的值{ans+=Map[tempS];//因为含有原始的值,所以先更新ans再+oncetempS+=once;//每次+once}cout<<ans<<endl;return 0;
}

原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/116538925

这篇关于第 2 届河北省大学生程序设计竞赛(河北省赛)-Problem K. Bitmap-题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/893908

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

uva 10025 The ? 1 ? 2 ? ... ? n = k problem(数学)

题意是    ?  1  ?  2  ?  ...  ?  n = k 式子中给k,? 处可以填 + 也可以填 - ,问最小满足条件的n。 e.g k = 12  - 1 + 2 + 3 + 4 + 5 + 6 - 7 = 12 with n = 7。 先给证明,令 S(n) = 1 + 2 + 3 + 4 + 5 + .... + n 暴搜n,搜出当 S(n) >=

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

C - Word Ladder题解

C - Word Ladder 题解 解题思路: 先输入两个字符串S 和t 然后在S和T中寻找有多少个字符不同的个数(也就是需要变换多少次) 开始替换时: tips: 字符串下标以0开始 我们定义两个变量a和b,用于记录当前遍历到的字符 首先是判断:如果这时a已经==b了,那么就跳过,不用管; 如果a大于b的话:那么我们就让s中的第i项替换成b,接着就直接输出S就行了。 这样

C语言程序设计(数据类型、运算符与表达式)

一、C的数据类型 C语言提供的数据类型: 二、常量和变量 2.1常量和符号常量 在程序运行过程中,其值不能被改变的量称为常量。 常量区分为不同的类型: 程序中用#define(预处理器指令)命令行定义变量将代表常量,用一个标识符代表一个常量,称为符合常量。 2.2变量 变量代表内存中具有特定属性的一个存储单元,用来存放数据,在程序运行期间,这些值是可以 改变的。 变

【秋招笔试】9.07米哈游秋招改编题-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收集 100+ 套笔试题,笔试真题 会在第一时间跟新 🍄 题面描述等均已改编,如果和你笔试题看到的题面描述

C语言程序设计(选择结构程序设计)

一、关系运算符和关系表达式 1.1关系运算符及其优先次序 ①<(小于) ②<=(小于或等于) ③>(大于) ④>=(大于或等于 ) ⑤==(等于) ⑥!=(不等于) 说明: 前4个优先级相同,后2个优先级相同,关系运算符的优先级低于算术运算符,关系运算符的优先级高于赋值运算符 1.2关系表达式 用关系运算符将两个表达式(可以是算术表达式或关系表达式,逻辑表达式,赋值表达式,字符

LeetCode 第414场周赛个人题解

目录 Q1. 将日期转换为二进制表示 原题链接 思路分析 AC代码 Q2. 范围内整数的最大得分 原题链接 思路分析 AC代码 Q3. 到达数组末尾的最大得分 原题链接 思路分析 AC代码 Q4. 吃掉所有兵需要的最多移动次数 原题链接 思路分析 AC代码 Q1. 将日期转换为二进制表示 原题链接 Q1. 将日期转换为二进制表示 思路分析