2021-2022-1 北京化工大学程序设计月赛(1) - 问题 G: 游戏的彩蛋 - 题解 - 哈希讲解

本文主要是介绍2021-2022-1 北京化工大学程序设计月赛(1) - 问题 G: 游戏的彩蛋 - 题解 - 哈希讲解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门

    • 游戏的彩蛋
      • 题目描述
      • 输入描述
      • 输出描述
      • 样例一
        • 输入
        • 输出
      • 样例二
        • 输入
        • 输出
  • 题目分析
  • 本题彩蛋
  • 哈希简介
  • KMP
  • 反思
  • AC代码


游戏的彩蛋

  • 游戏的彩蛋

时间限制:1秒
空间限制:256M


题目描述

Ron Milner 在 1977 1977 1977 年的游戏 《 S t a r s h i p 1 Starship\ 1 Starship 1》中隐藏了彩蛋,玩家进行一系列操作后游戏会说:“HI RON!”并赠送玩家 10 10 10条命。

随着时间的流逝 Ron Milner 忘记了彩蛋如何触发,但确实在程序里找到了HI RON!的字样。

小T的男神做了一款游戏,程序十进制序列为 a a a,小T认为某彩蛋(十进制序列为 b b b)藏在其中,想让你确认序列 a a a中是否有一段连续的序列 b b b,如果有,就认为该彩蛋藏在游戏中。

  • 例如程序的序列 a a a53 81 33 93 93 31 74, 彩蛋的序列 b b b93 93 31 74(能在 a a a中找到连续的序列 b b b),就认为程序中隐藏有该彩蛋。

  • 例如程序的序列 a a a23 93 31 74 22,彩蛋的序列 b b b72 74 73 23(不能在 a a a中找到连续的序列 b b b),就认为此程序中没隐藏该彩蛋。


输入描述

输入包括 3 3 3

  • 1 1 1行是空格隔开的两个整数 m n m\ n m n,其中 1 ≤ m ≤ 1 0 5 , 1 ≤ n ≤ 1 0 5 1\leq m\leq 10^5,1\leq n\leq 10^5 1m105,1n105,分别代表程序的序列 a a a和彩蛋的序列 b b b的长度(十进制数的个数)
  • 2 2 2行是空格隔开的 m m m个整数 a 1 a 2 ⋯ a m a_1\ a_2\ \cdots\ a_m a1 a2  am,代表程序的序列 a a a,其中 0 ≤ a i ≤ 255 ∀ i ∈ { 1 , 2 , ⋯ , m } 0\leq a_i \leq 255\ \ \forall i\in \{1,2,\cdots, m\} 0ai255  i{1,2,,m}
  • 3 3 3行是空格隔开的 n n n个整数 b 1 b 2 ⋯ b n b_1\ b_2\ \cdots\ b_n b1 b2  bn,代表程序的序列 b b b,其中 0 ≤ b i ≤ 255 ∀ i ∈ { 1 , 2 , ⋯ , n } 0\leq b_i \leq 255\ \ \forall i\in \{1,2,\cdots, n\} 0bi255  i{1,2,,n}

输出描述

输出包括 1 1 1 1 1 1个字符串

  • 如果程序中隐藏有该彩蛋,输出Yes
  • 如果程序没有隐藏该彩蛋,输出No

样例一

输入
7 4
53 81 33 93 93 31 74
93 93 31 74
输出
Yes

样例二

输入
5 4
23 93 31 74 22
72 74 73 23
输出
No

题目分析

这道题说白了就是找序列 a a a中是否存在连续子序列 b b b

a a a中元素个数和 b b b中元素个数都是 1 e 5 1e5 1e5级别,使用KMP即可复杂度O(n+m)$地通过此题。

如果觉得KMP比较麻烦,使用哈希也可解决。


本题彩蛋

在本题的题目描述第一行游戏 《Starship 1》中隐藏了彩蛋中隐藏了彩蛋。快速并连续地点击这句话中的彩蛋二字5次,即可得到本题解题思路: K M P KMP KMP


哈希简介

本题的哈希算法主要就是将一系列数映射成一个数,进而快速比较两个序列是否相同(如果两个序列用同样的方法映射成的两个数相同,就可以很大程度上认为两个序列完全相同)

那么问题主要就在于如何将一系列数映射成一个数,这个问题蒟蒻之前写过一些,相同部分就不再做过多赘述。

👉最基本的哈希算法

假如给你一系列的个位数 a a a,又给你了一系列的个位数 b b b,问你能否在 a a a中找到连续子序列 b b b, 那么不就是这道题的简化版吗?

序列 a a a: 5 7 4 9 6 1 2 6 5\ 7\ 4\ 9\ 6\ 1\ 2\ 6 5 7 4 9 6 1 2 6,序列 b b b: 9 6 1 9\ 6\ 1 9 6 1

首先我能不能把序列 a a a转化成 1 1 1个数?

当然,我们可以很容易地把序列 a a a: 5 7 4 9 6 1 2 6 5\ 7\ 4\ 9\ 6\ 1\ 2\ 6 5 7 4 9 6 1 2 6转化成一个数 57496126 57496126 57496126。同理可以把序列 b b b转化成 1 1 1个数 961 961 961

但是序列 b b b的长度是 3 3 3,序列 a a a的长度是 8 8 8,要想找到序列 a a a中是否有连续的子序列正好是 b b b,即找 a a a中是否有长度为 3 3 3的序列正好是 b b b
如果是,那么这个长度为 3 3 3的序列转化成一个数后必须是 961 961 961(和 b b b相等)

a a a中长度为 3 3 3的序列转换成一个数后都是什么呢?

3 3 3个数 → 574 \rightarrow\ 574  574,之后是 749 749 749,之后 496 496 496,然后 961 961 961 612 612 612 126 126 126。其中正好第 3 3 3个数是 961 961 961(和 b b b转化成的数相等)。因此我们认为序列 a a a中能找到连续子序列 b b b

数与数的比较复杂度是 O ( 1 ) O(1) O(1),但是能不能快速将序列 a a a转换成很多长度为 3 3 3的数呢?

如果三个三个转换的化,每次转换都需要计算 3 3 3次,共需要转换 l e n ( m ) − 3 + 1 len(m)-3+1 len(m)3+1次,记 3 3 3 l e n ( b ) len(b) len(b),复杂度为 O ( l e n ( b ) ∗ ( l e n ( m ) − l e n ( b ) ) ) O(len(b)*(len(m)-len(b))) O(len(b)(len(m)len(b))),还是很慢。

但是前一个的值可以为后一个所用。

3 3 3个数是 574 574 574 1 1 1 4 4 4个数是 749 749 749,中间有相同的部分 74 74 74。怎么由 574 574 574得到 749 749 749呢? 759 = ( 574 − 5 ∗ 1 0 2 ) ∗ 10 + 9 759=(574-5*10^2)*10+9 759=(5745102)10+9,这样计算新的哈希值复杂度就是 O ( 1 ) O(1) O(1)

但上面都是以十进制为例子说的,其实最好以一个素数为进制(比如 131 131 131)。同时也不能用一个特别大的数来存,因此要取模。

加上这两点,我们只需要把上述的十进制中的 10 10 10换成 b a s e base base(比如 131 131 131),并且计算后及时取模就可以了。


KMP

教程很多,数据结构课也可能讲,就不再赘述了。


反思

我承认数据还是太弱了,python的find甚至暴力都能过☠

但是,真正掌握了算法才是最重要的。


AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;const int mod = 100001651;
#define Yes {puts("Yes");return 0;}
#define No {puts("No");return 0;}
int a[100010],b[100010];
int base=131; //131进制
int main()
{int m,n;cin>>m>>n;if(m<n)No;for(int i=0;i<m;i++)scanf("%d",&a[i]);for(int i=0;i<n;i++)scanf("%d",&b[i]);ll hash=0; // 哈希值for(int i=0;i<n;i++)hash = (hash*base+b[i])%mod; // 算出序列b的哈希ll Pow=1; // 计算base的n-1次方for(int i=1;i<n;i++)Pow=(Pow*base)%mod; // 再算出base的(n-1)次方(如上述讲解中的100就是10的3-1次方)ll hashA=0; // 哈希值for(int i=0;i<n;i++) // 先算出前n个数的哈希(第一个长度为n的序列)hashA=(hashA*base+a[i])%mod;if(hashA==hash) // 如果哈希值恰好等于序列b的哈希值,就认为序列a的前n个元素正好是bYes;for(int i=n;i<m;i++) // 剩下的每个可以作为结尾的数{hashA = (((hashA - a[i-n]*Pow)%mod+mod*2)*base+a[i])%mod; // 如前面介绍,减去前面不属于这n个数的数,加上新的一个属于这n个数的数if(hashA==hash) // 相等就认为存在Yes;}No; // 都不相等肯定不存在return 0;
}

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

这篇关于2021-2022-1 北京化工大学程序设计月赛(1) - 问题 G: 游戏的彩蛋 - 题解 - 哈希讲解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

国产游戏崛起:技术革新与文化自信的双重推动

近年来,国产游戏行业发展迅猛,技术水平和作品质量均得到了显著提升。特别是以《黑神话:悟空》为代表的一系列优秀作品,成功打破了过去中国游戏市场以手游和网游为主的局限,向全球玩家展示了中国在单机游戏领域的实力与潜力。随着中国开发者在画面渲染、物理引擎、AI 技术和服务器架构等方面取得了显著进展,国产游戏正逐步赢得国际市场的认可。然而,面对全球游戏行业的激烈竞争,国产游戏技术依然面临诸多挑战,未来的

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo