2021-2022-1 北京化工大学程序设计月赛 - 问题 G: 游戏的彩蛋 - 题解 - 哈希讲解
Posted Tisfy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-2022-1 北京化工大学程序设计月赛 - 问题 G: 游戏的彩蛋 - 题解 - 哈希讲解相关的知识,希望对你有一定的参考价值。
游戏的彩蛋
时间限制: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 a是
53 81 33 93 93 31 74
, 彩蛋的序列 b b b是93 93 31 74
(能在 a a a中找到连续的序列 b b b),就认为程序中隐藏有该彩蛋。 -
例如程序的序列 a a a是
23 93 31 74 22
,彩蛋的序列 b b b是72 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 1≤m≤105,1≤n≤105,分别代表程序的序列 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\\} 0≤ai≤255 ∀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\\} 0≤bi≤255 ∀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=(574−5∗102)∗10+9,这样计算新的哈希值复杂度就是 O ( 1 ) O(1) O(1)了
但上面都是以十进制为例子说的,其实最好以一个素数为进制(比如
131
以上是关于2021-2022-1 北京化工大学程序设计月赛 - 问题 G: 游戏的彩蛋 - 题解 - 哈希讲解的主要内容,如果未能解决你的问题,请参考以下文章 2021-2022-1 北京化工大学程序设计月赛 - 问题 H: 彩蛋的游戏 - 题解 - 2021-2022-1 北京化工大学程序设计月赛 - 问题 H: 彩蛋的游戏 - 题解 - 新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)- 猴子排序的期望