简介

Hash,将一个字符串映射到一个数字上。

计算Hash

计算Hash的方法有很多种,比如说在密码学中常用的 \(\texttt{MD5}\) 和 \(\texttt{SHA256}\) 等。

但是我们一般使用一个简单的方法:

  • 将字符串看成一个 \(B\) 进制数。(\(B \ge \textbf{字符集大小}\))
  • 将这个 \(B\) 进制数对 \(p\) 取模,要求 \(B,p\) 互质。

显然,如果有 \(p+1\) 个互不相同的字符串,那么一定有至少一对 \(\operatorname{Hash}\) 相等的字符串。

所以,\(p\) 一般都很大,如 \(2^{64},2^{63},10^{9}+7\) 等。

注:大多数情况下,\(10^{9}+7\) 仍然不够用,因为当有 \(\sqrt{p}\) 个字符串时,\(\operatorname{Hash}\) 相同(我们称之为Hash冲突)的概率就很高了。

Tip:在C++中,如果用 unsigned long long 来保存,那么可以考虑自然溢出,这样其实自带 \(p=2^{64}\)。

其实 \(p\) 最好为质数,但是一般不需要。

后文中,用 \(\operatorname{hash}(x)\) 表示字符串 \(x\) 的Hash值。

前缀Hash递推

预处理字符串 \(s\) 的所有前缀子串 \(s[1:i]\) 的Hash \(H[i]\),\(H\) 就是 \(s\) 的前缀Hash,后缀Hash同理。

那么有一个显然的递推公式:

\[H[i]=H[i-1]\times B+\operatorname{ToInteger}(s[i]) \pmod{p}
\]

前缀Hash可以处理以下问题:

  • 给出几个字符串,求一个模式串 \(s\) 是多少个字符串的前缀。

将所有字符串的前缀Hash求出来,合并成一个有序数组(或者 std::set),然后求出 \(\operatorname{hash}(s)\),将 \(\operatorname{hash}(s)\) 在那个数组/set上二分。

快速计算子串Hash

先使用上面章节的方法递推出前缀Hash \(H\)。

那么子串 \(s[l:r]\) 的Hash计算公式为:

\[\operatorname{hash}(s[l:r])=H[r]-H[l-1]\times B^{r-l+1} \pmod{p}
\]

就可以在 \(O(\log n)\)(如果使用光速幂就是 \(O(1)\))求字符串中的任意连续字串的hash了。

用Hash匹配字符串

如果 \(\operatorname{hash}(x)=\operatorname{hash}(y)\),那么 \(x=y\)。

由于hash冲突的存在,可能并不准确,但是只要 \(p\) 尽可能的大就行。

综合:P2852 [USACO06DEC]Milk Patterns G

给出一个长度为 \(n\) 数列 \(A\),问出现次数为 \(K\) 的字串长度最大是多少?

\(1 \le K \le n \le 20000,1 \le A_i \le 1000000\)

第一道没看题解A掉的紫题

正解SAM,但是可以用Hash水过。

预处理前缀Hash,二分字串长度 \(L\),对于每一个长度为 \(L\) 的子串计算Hash,用 std::unordered_map 统计一下就好。

时间复杂度 \(O(n\log^{2} n)\)。

代码:(写到一半二分不会写,还要请教@exited,雾)

#include <bits/stdc++.h>
#define DEBUGGING 1
#define debug(...) if(DEBUGGING){printf(__VA_ARGS__);putchar('\n');} using namespace std; int n,k;
int a[20005];
int l,r;
int mid;
unsigned long long qzhash[20005];
const int base =1000001;
const unsigned long long mod = 2e63; #define int unsigned long long
int pow(int a,int b,int mod) {
#define MAG (1ull)
int ans=1;
for(; b; b>>=1,a=MAG*a*a%mod) {
if(b&1) {
ans=MAG*ans*a%mod;
}
}
#undef MAG
return ans;
}
#undef int unsigned long long any_hash(int l,int r){
return (qzhash[r]-(qzhash[l-1]*pow(base,r-l+1,mod))%mod)%mod;
} unordered_map<unsigned long long,int> mmap;
int max_mm = 0; bool check(int length){
max_mm=0;
mmap.clear();
for(int l=1,r=length;l<=n&&r<=n;l++,r++){
unsigned long long current_hash=any_hash(l,r);
mmap[current_hash]++;
max_mm = max(max_mm, mmap[current_hash]);
}
return max_mm >= k;
}
int ans=0;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
qzhash[i]=qzhash[i-1]*base%mod;
qzhash[i]+=a[i];
qzhash[i]%=mod;
}
l=1,r=n;
while(l<r){
mid=(l+r)>>1;
if(check(mid)){
l=mid+1;
ans=mid;
}
else{
r=mid;
}
}
cout<<ans;
return 0;
}

Hash——温暖人心的算法的更多相关文章

  1. 【bzoj3207】花神的嘲讽计划Ⅰ Hash+STL-map+莫队算法

    题目描述 背景 花神是神,一大癖好就是嘲讽大J,举例如下: “哎你傻不傻的![hqz:大笨J]” “这道题又被J屎过了!!” “J这程序怎么跑这么快!J要逆袭了!” …… 描述 这一天DJ在给吾等众蒟 ...

  2. consistent hash(一致性哈希算法)

    一.产生背景 今天咱不去长篇大论特别详细地讲解consistent hash,我争取用最轻松的方式告诉你consistent hash算法是什么,如果需要深入,Google一下~. 举个栗子吧: 比如 ...

  3. hash算法总结收集

    hash算法的意义在于提供了一种快速存取数据的方法,它用一种算法建立键值与真实值之间的对应关系,(每一个真实值只能有一个键值,但是一个键值可以对应多个真实值),这样可以快速在数组等条件中里面存取数据. ...

  4. 常见hash算法的原理

    散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法.顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙. 散列表(Hash table,也叫 ...

  5. PHP中各种Hash算法性能比较

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  6. 分布式算法(一致性Hash算法)

    一.分布式算法 在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括: 轮循算法(Round Robin).哈希算法(HASH).最少连接算法(Least Connection).响应速度算法( ...

  7. Hash算法入门指南(聊点不一样的算法人生)

    前言 很多人到现在为止都总是问我算法该怎么学啊,数据结构好难啊怎么的,学习难度被莫名的夸大了,其实不然.对于一个学计算机相关专业的人都知道,数据结构是大学的一门必修课,数据结构与算法是基础,却常常容易 ...

  8. 几种常用hash算法及原理

    计算理论中,没有Hash函数的说法,只有单向函数的说法.所谓的单向函数,是一个复杂的定义,大家可以去看计算理论或者密码学方面的数据.用“人 类”的语言描述单向函数就是:如果某个函数在给定输入的时候,很 ...

  9. 海量数据挖掘MMDS week2: 频繁项集挖掘 Apriori算法的改进:基于hash的方法

    http://blog.csdn.net/pipisorry/article/details/48901217 海量数据挖掘Mining Massive Datasets(MMDs) -Jure Le ...

  10. logging日志模块,hashlib hash算法相关的库,

    logging: 功能完善的日志模块 import logging #日志的级别 logging.debug("这是个调试信息")#级别10 #常规信息 logging.info( ...

随机推荐

  1. 深入剖析Sgementation fault原理

    深入剖析Sgementation fault原理 前言 我们在日常的编程当中,我们很容易遇到的一个程序崩溃的错误就是segmentation fault,在本篇文章当中将主要分析段错误发生的原因! S ...

  2. UEC 利用代理/委托写一个生命组件

    首先基于ActorComponent创建一个组件 HealthComponent,将需要的变量与函数创建 #include "CoreMinimal.h" #include &qu ...

  3. 走进shell

    走进shell 在Linux早起,还没有出现图形化,超哥和其他系统管理员都只能坐在电脑前,输入shell命令,查看控制台的文本输出. 在大多数Linux发行版里,例如centos,可以简单的用组合键来 ...

  4. 树上启发式合并(dsu on tree)

    树上启发式合并属于暴力的优化,复杂度O(nlogn) 主要解决的问题特点在于: 1.对于树上的某些信息进行查询 2.一般问题的解决不包含对树的修改,所有答案可以离线解决 算法思路:这类问题的特点在于父 ...

  5. 2022icpc新疆省赛

    菜鸡第一次打icpc 记录一下历程 习惯#define int long long 以下皆是按照我认为的难易顺序排序 K. 看题意大概就是说求从L加到R 1 ios::sync_with_stdio( ...

  6. 想开发DAYU200,我教你

    摘要:本文主要介绍OpenHarmony富设备DAYU200开发板的入门指导. 本文分享自华为云社区<DAYU200开发指导>,作者: 星辰27. 1 概述 DAYU200开发板属于Ope ...

  7. 【笔记】区间DP

    记录一些基础的区间 \(\text{DP}\) 题. 0x00 AT_dp_n N - Slimes 最板的区间 \(\text{DP}\) . 记 \(f[i][j]\) 表示合并 \(i\sim ...

  8. Inventor 2021保姆级安装教程

    Inventor 2021 WIN10 64位安装步骤: 1.先使用"百度网盘客户端"下载INT21_CN_x64安装包到电脑磁盘里,并鼠标右击进行解压缩,安装前先断网,然后找到I ...

  9. 基于python的数学建模---机场航线设计

    数据集 拿走: 链接:https://pan.baidu.com/s/1zH5xhpEmx2_u5qO9W4gCkw 提取码:2wl5 数据集来自航空业,有一些关于航线的基本信息.有某段旅程的起始点和 ...

  10. day19-web开发会话技术01

    WEB开发会话技术01 1.会话 Web开发中,用到的4种会话跟踪技术 - 博客园 (cnblogs.com) 会话的基本介绍 什么是会话? 会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服 ...