双值Hash

简单介绍

  • Hash的应用:Hash其实就像一个加密过程,很多加密算法都会用到Hash,像GitHub中生成的token值也是Hash的结果。

  • Hash冲突:简单来说就是不同的数映射到了同一个值,防止碰撞的最有效方法就是扩大Hash值的取值空间,也就是最好选用一个大质数(具体原因参考生日悖论/生日攻击:生日攻击是一个计算机密码学中的术语)。

  • 数学原型生日问题:一个班需要多少人,能保证有两个人的生日是一样的。鸽笼原理可能会得出366人,但是实际情况远少于366。这意味着Hash碰撞的可能性远比想象的高,实际上有一个近似的公式\(\sqrt{\frac{\pi}{2}N}\)可以算出50%Hash碰撞所需要的计算次数。这个公式告诉我们Hash碰撞所需耗费的计算次数,和取值空间的平方根是一个数量级。

进入正题

双值Hash就是用两个不同的mod值来计算Hash,如果两个Hash值都相等才认为是同一个字符串,Hash冲突概率降低了很多,但是常数大,容易被卡。时间上:自然溢出法<单Hash+大质数<双Hash+大质数。

  • Hash的几个常用公式:(虽然说本题不需要用到)

    • Hash递推:

      Hash[0]=0;
      Hash[i]=(Hash[i-1]*p+s[i]-'a'+1)%mod;
    • 区间Hash值:

      Hash[L...R]=(Hash[R]-Hash[L]*p^(R-L+1)+mod)%mod;这里减法可能会溢出

使用Hash的几个需要注意的地方

  • 在复杂度允许的情况下,尽量采用多Hash(不过一般双值Hash就够)

  • 比赛时能不用自然溢出就不要(平时刷题如果用自然溢出被卡可以及时换掉,但是比赛时如果用自然溢出,OI赛制就GG了)

  • 模数用大质数这个不用说了

  • 并且进制数不要选太简单的,比如 233和 13131 这样的,尽量大一点,比如1313131和233333,太小容易被卡。

  • 以及要合理应对各种卡hash方法的最好方法就是自己去卡一遍hash,详情请参考BZOJ hash killer系列。(各位巨佬可以尝试一下hash killer 3啊233333)

例题

题目链接:

给出N个字符串,输出不同字符串的个数。

#include <iostream>
#include <cstring>
#include <algorithm> using namespace std;
typedef unsigned long long ull;
const ull mod1=212370440130137957ll;
const ull mod2=(1<<30);
const int maxn=10001;
const int base=233333;
char a[maxn];
int n;
struct node{ull x,y;
bool operator < (const node& a)const{
return a.x==x?a.y<y:a.x<x;
}
}f[maxn];
inline ull hash1(char s[]){
ull ans=0,len=strlen(s);
for(int i=0;i<len;++i)ans=(ans*base+(ull)s[i])%mod1;
return ans;
}
inline ull hash2(char s[]){
ull ans=0,len=strlen(s);
for(int i=0;i<len;++i)ans=(ans*base+(ull)s[i])%mod2;
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%s",a);
f[i].x=hash1(a);
f[i].y=hash2(a);
//cout<<f[i].x<<" "<<f[i].y<<endl;
}
sort(f+1,f+1+n);
int ans=0;
for(int i=1;i<=n;++i){
if(f[i].x!=f[i+1].x||f[i].y!=f[i+1].y)ans++;//非相同字符串两个Hash值同时相等的概率非常小
}
printf("%d\n",ans);
return 0;
}

# 双值Hash的更多相关文章

  1. 2018-10-14普及模拟赛」Hash 键值 (hash)

    今天,带大家看一看一道思维题... Hash 键值 (hash) 题目描述 Marser沉迷hash无法自拔,然而他发现自己记不住hash键值了-- Marser使用的hash函数是一个单纯的取模运算 ...

  2. Southwestern Europe Regional Contest 2014 题解

    时间:2017/9/8 题目8/10 Rank 5/150 体会:三星的题目和国内区域赛差距大,大多数题读懂题意就能做,所以静心读题是关键,套路性太深. A: 题意:给出一个算式,算式中的数字用大写字 ...

  3. CF 494 F. Abbreviation(动态规划)

    题目链接:[http://codeforces.com/contest/1003/problem/F] 题意:给出一个n字符串,这些字符串按顺序组成一个文本,字符串之间用空格隔开,文本的大小是字母+空 ...

  4. python中那些双下划线开头得函数和变量--转载

    Python中下划线---完全解读     Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用'from module import *'导入 __xxx__ 系统定义名字 __x ...

  5. 从Hash Killer I、II、III论字符串哈希

    首先,Hash Killer I.II.III是BZOJ上面三道很经典的字符串哈希破解题.当时关于II,本人还琢磨了好久,但一直不明白为啥别人AC的代码都才0.3kb左右,直到CYG神犇说可以直接随机 ...

  6. python中那些双下划线开头得函数和变量

    Python中下划线---完全解读     Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用’from module import *’导入 __xxx__ 系统定义名字 __x ...

  7. 【字符串算法1】 再谈字符串Hash(优雅的暴力)

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  [字符串算法1] 字符串Hash 老版原文: RK哈希(Rabin_Ka ...

  8. 字符串hash&&对字符串hash的理解

     对字符串hash的一些总结: 1,首先,我们在转化的时候,取底的时候一般是取131这些数,因为要避免不同的字符串对应相同的hash值这种情况的出现.如果卡精度的时候,我们可以采取双模数的方式尽量减少 ...

  9. 字符串hash的学习部分 可以算是模板?

    资料来自于http://www.bilibili.com/video/av7230433/ 定义这个字符串为s ①单hash hash[i] = (hash[i - 1] * p + idx(s[i] ...

随机推荐

  1. vue3.x 错误记录

    1:css报错 This dependency was not found: * !!vue-style-loader!css-loader?{"minimize":false,& ...

  2. keras 模型简介

    keras模型在keras中主要有两种模型,顺序模型,以及模型类(类的内部有函数) model.layers 是层的列表,他们组成了模型 model.inputs 是模型输入的张量 model.out ...

  3. 观察者模式在android网络监控下的运用

    github:https://github.com/shonegg/NetMonitor 一.对观察者模式的理解: 1.观察者模式,又叫发布-订阅(Publish/Subscribe)模式,定义的是对 ...

  4. React的基本认识

    1.1.1. 官网 1) 英文官网: https://reactjs.org/ 2) 中文官网: https://doc.react-china.org/ 1.1.2.  介绍描述 1) 用于构建用户 ...

  5. ORM SQLAlchemy 简介

    对象关系映射(Object Relational Mapping,简称ORM使用DB-API访问数据库,需要懂 SQL 语言,能够写 SQL 语句,如果不想懂 SQL,又想使用关系型数据库,可以使用 ...

  6. React的Virtual DOM厉害了

    React 的伟大之处就在于,提出了Virtual DOM这种新颖的思路,并且这种思路衍生出了React Native,有可能会统一Web/Native开发. 在性能方面,由于用到了Virtual D ...

  7. golang gorm框架的默认时区问题

    gorm框架的时区是在连接数据库时设置的, 如下

  8. BufferedWriter中write与close函数使用

    BufferedWriter 是一个缓冲字符输出流,可以将要输出的内容先缓冲到一个字符数组中,等字符数组满了才一次性写到输出流内,默认的字符数组长度为8192.使用BufferedWriter 时需要 ...

  9. 静态库和动态库的区别和win平台和linux平台代码实现

    静态库和动态库的区别   什么是库 库是写好的,现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说,库是一种可 ...

  10. 花椒直播基于golang的中台技术实践

    https://github.com/gopherchina/conference/blob/master/2019/2.7%20花椒直播基于golang的中台技术实践%20-%20周洋.pdf 花椒 ...