12.10闲话

发布时间 2023-12-10 19:34:15作者: Vsinger_洛天依

今天和HS_xh吃饭互相爆典

先是我在学校食堂买了个臭鸡蛋

然后我"吾日三省吾身:买到臭鸡蛋了吗?"

HS_xh:"买到臭鸡蛋了吗?怎么买到的?买到了怎么办"

我:“哥我错了,别唐了”

HS_xh:"我是唐玄宗"

我:\("?"\)

然后HS_xh没带勺子和筷子但是买了碗麻辣烫

HS_xh:"哥能不能把饭卡给我我买个勺子去"(\(ta\)没带饭卡)

我:"你看你这不有个串吗,用这个插着吃"

然后我说我去买瓶水

HS_xh:"哥给我买个勺"

我:"彳亍"

然后我到了超市给忘了,回来就看到HS_xh在拿串吃

然后我才想起来我忘了但是我懒得去了

HS_xh正在拿串吃麻辣烫

我:"哥我错了你能不能插着吃"

HS_xh:"我这不吃里头粉呢吗"(说着吃了个丸子)

然后ta就开始用串插丸子,一下子插了五六个丸子但是一个都不吃

我:"?"

我:"你这是反串吧,你看别人都是吃已经穿完的,你是穿已经吃完的"

然后我好像意识到我说的什么不对但是接着说了

"你看你这个丸子上有黑点,你这是反串黑"

然后我就看到HS_xh用...带着6个丸子的串来扒里面的火腿肠

然后我就开始笑,然后TA也开始笑,但是我不知道我在笑啥

接着HS_xh就开始...随机挑选那个串上的丸子吃

我就说这是随机算法

然后TA用两个火腿肠做了个锤子开始做锤击的动作

然后我说你是不是人杰因为唐人杰

接着我说了一句我这个饼不甜啊说明做饭的不是唐

ta说我这个倒是很甜所以应该是唐

我不知道为啥说了句我是盐

接着回机房了

然后路上我就开始唐

"发明鼠标之前的人们恐怕用的是触屏版"

"键盘出现之前的人们都是用虚拟键盘打代码的"

然后发现下雪了HS_xh叫我看但是我只看到学校那3个特别晃眼的大灯所以没有欣赏雪景

HS_xh:"好冷啊"

我:"下雪不冷化雪冷,你今天是不是学化学了'

然后就到机房了

三十遍提交镇楼

image

CSP-J神码辟邪

image

经过K8的提醒我成功意识到我不应该学流因为我是菜狗

好像也是,我普及组OJ的状压,KMP,AC自动机都没打,单调队列优化DP最多勉强打几下的废物为啥学网络流去了

所以去打字符串Hash了

看看能不能打懂吧


坚持每天推歌直到不知道推啥为止

所以我带上了耳机

往来穿行于城市之中

未曾留意多少风景与众不同

跟随机械转动的时钟

规划着步伐的节奏

如果说所有悲欢终将在喧嚣中淹没

总有人与我不期而遇在迷茫的路口

为我再次寻回遗失在现实角落的梦

为世界带来久违的温柔

风的欢笑雨的哭声

融化裹挟了谁平凡的感动

身后闪烁万家灯火

将人间的故事诉说给星空

无论春夏无论秋冬

无论多少岁月将我们分隔

摘下耳机时眼眶依旧会微红

即便明天也像今天一样

按部就班一如即往

无法脱离航道

漂浮在不息的人潮

你仍在阴云的缝隙中撒下阳光

指引迷途的蝴蝶发现生长的芬芳

多年之后当夏天再次来到

我是否还能再听见你歌唱

在那暮色渲染

蝉声如浪的街角

那时我是否也能够像你一样

给予每个雨中的歌者

最温暖的拥抱

如果说所有悲欢终将在喧嚣中淹没

总有人与我不期而遇在迷茫的路口

为我再次寻回遗失在现实角落的梦

为世界带来久违的温柔

风的欢笑雨的哭声

融化裹挟了谁平凡的感动

身后闪烁万家灯火

将人间的故事诉说给星空

无论春夏无论秋冬

无论多少岁月将我们分隔

摘下耳机时眼眶依旧会微红

戴上耳机依旧是你描绘的梦

字符串Hash

诶我好像学过,哦我学的是KMP不是字符串哈希

定义一个把字符串映射到整数的函数 \(f\) ,称为Hash函数。

函数 \(f\) 可以帮我们判断两个字符串是否相等

思想

Hash 的核心思想在于,将输入映射到一个值域较小、可以方便比较的范围。

然后字符串Hash也是如此

字符串Hash中,值域需要小到能够快速比较,因为存在哈希冲突,值域不能太小

性质

具体来说,哈希函数最重要的性质可以概括为下面两条:

  • Hash 函数值不一样的时候,两个字符串一定不一样;

  • Hash 函数值一样的时候,两个字符串不一定一样(但有大概率一样,且我们当然希望它们总是一样的)。

哈希冲突: Hash 值一样但字符串不一样的现象

实现

对于一个长度为 \(l\) 的字符串 \(s\) 来说,我们可以这样定义 Hash 函数:
\(f(s) = \sum_{i=1}^{l} s[i] \times b^{l-i} \pmod M\) 。例如,对于字符串 \(xyz\) ,其哈希函数值为 \(x\times b^2+y\times b+z\)

如何选择\(M\)\(b\) \(?\)

\(M\)至少要比字符串中最大的字符要大,\(b\)可以随便选

//低效率版本
#define int long long
const int M=1e9+7;
const int B=13331;
inline int hash(const std::string&s){
    int res=0;
    for(int i=0;i<s.size();++i)
        res=(res*B+s[i])%M;
    return res;
}
bool cmp(const std::string&s,const std::string&t) {
    return hash(s)==hash(t);
}

优化

  • 哈希冲突

    为了减少被毒瘤出题人卡的情况我们可以选择多\(\bmod\)几个大质数

    比如\(1e9+7\),\(1e9+9\),\(998244353\)

    不怕死的可以ull自然溢出但是我不敢

  • 多次询问子串哈希

    先预处理出每个前缀的哈希值,将哈希值看成一个 \(b\) 进制的数对 \(M\) 取模的结果,每次就能快速求出子串的Hash值

    \(f_i(s)\) 表示 \(f(s[1..i])\) ,即原串长度为 \(i\) 的前缀的哈希值,那么有 \(f_i(s)=s[1]\cdot b^{i-1}+s[2]\cdot b^{i-2}+\dots+s[i-1]\cdot b+s[i]\)

    用类似前缀和的方式快速求出 \(f(s[l..r])\) ,有字符串 \(s[l..r]\) 的Hash值为 \(f(s[l..r])=s[l]\cdot b^{r-l}+s[l+1]\cdot b^{r-l-1}+\dots+s[r-1]\cdot b+s[r]\)

    \(f(s[l..r])=f_r(s)-f_{l-1}(s) \times b^{r-l+1}\),因此可以快速得到子串的哈希值。其中 \(b^{r-l+1}\) 可以 \(O(n)\) 的预处理然后 \(O(1)\) 回答每次询问