Hash更进一步(Hash字符串——BDKRHash)
来源:互联网 发布:淘宝无线端短连接 编辑:程序博客网 时间:2024/05/22 14:30
在这里先道歉,因为博主实在太蒻,不会写Hash冲突的解决的博客,害怕误人子弟,所以决定写一篇Hash字符串的博客来弥补,实在是罪过、罪过。
Hash字符串(第一次接触Hash的小伙伴可以去看一下我的Hash初步,仅供参考)是一种很神奇的操作,历史很多计算机专业的学者,也对它进行了一系列的探讨与开发,所以现在有很多种Hash字符串的处理方式,最为常用的有三种BKDRHash、APHash、DJBHash()等等。
有一位大佬的博客对几种常见的Hash字符串处理做了统计、实践,大家可以去他的博客看一下,反正比蒟蒻博主我的博客强太多了http://www.cnblogs.com/Stomach-ache/p/3724836.html。
经过一番激烈的角逐,BDKRHash最终脱颖而出,成为了我们当之无愧的冠军。让我们有请图灵先生为它……不对,扯远了。所以今天要给大家介绍的就是BDKRHash了。
再说BDKRHash之前,先要给大家引导一下。
通常我们针对一个字符串处理,最容易想到的是将每一个字母的ASCLL码值相加得到一个字符串的Hash值。但这样做会导致我们建立的这个Hash表冲突非常多,这显然是不合理的,是一个超级烂的Hash。更进一步,大家可能会想到给每一个位置都确定一个不同的值,在用该位置上的字母的ASCLL码值 * 这个位置的固定值。这样做会有效的减小冲突,但还是不够。那么如果我们把每一个字符串的值都由它的子串 * 一个系数决定,最后在利用取余,就会更大程度避免冲突(当然也不是绝对的),这就是BDKRHash的基本思路。
BDKRHash的公式如下:
1. hashvalue[i]=(hashvalue[i-1]*seed+str[i]-'a'+1)%P(也可以用ASCLL码值,但容易爆)2.Hashvalue[l……r]=(hashvalue[r]-hashvlaue[l-1]*seed^(r-l+1))%P(注意第一个Hashvalue与hashvalue不同)
据某大佬说,BDKRHash的冲突在5%以内,但不是完全没有,很多时候,大家都喜欢把大P的值取int的最大值或者是long long的最大值,但是如果出题人充满心机,就很容易把你的代码卡掉。所以在写的时候尽量使用一个大的质数,例如:10^9+7和10^9+9。但也不是绝对的,这玩意儿也有可能会被卡掉。就以noip 2015模拟赛中的好文章为例。给大家看一下,出题人的心机。
——摘自某不明大佬的博客
【题目描述】
nodgd 写了一篇文章,自认为这是一篇好文章。nodgd 的文章由n个小写英文字母组成。文章的一个子串指的是文章中的一段连续的字母,子串的长度就是这一段的字母个数。nodgd 在文章中用了排比、对偶、前后照应之类的手法,所以就有很多个子串是相同或者相近的。为了向大家证明这是一篇好文章,nodgd决定给自己的文章进行评分。nodgd 首先确定了一个整数m,然后统计出文章中有多少个不相同的长度为m的子串,这个数量就是文章的评分。然而,nodgd懒得老老实实计算这个评分了,就把任务丢给了你。
【输入】
第一两个整数n,m,表示文章的长度和需要统计的子串长度。
第二行包含一个长度为?的只包含小写字母的字符串。
【输出】输出一行一个整数,表示文章的评分。 【样例输入】5 3aaaab 【样例输出】2提示 【样例解释 1】 长度为3的子串有3个,分别是 aaa,aaa,aab,其中不同的只有2个。 【样例输入 2】 9 3 abcabacba 【样例输出 2】 7 【样例解释 2】 共有7个长度为3的子串,每个长度为3的子串都不同。 【数据范围】 于 30%的数据,1 ≤ m ≤ n ≤ 200; 于 50%的数据,1 ≤ m ≤ n ≤ 2000; 于另外 20%的数据,1 ≤ m ≤ 50 ≤ n ≤ 200000; 于100%的数据,1 ≤ m ≤ n ≤ 200000;
首先据出题人介绍了,很多种算法,因为楼主没有保存出题人的心机图,所以楼主也不太记得具体是哪些。
首先肯定是用BDKRHash,为什么?不是因为他得分高,而是因为,BDKRHash的第二个性质,比较两个字符串的Hash值即可。
单BDKRHash,如果用自然溢出大法,用一个神秘的公式据说就可以卡大部分,只能得30分。如果用10^9或10^7也很容易卡掉。
利用BDKRHash的方法,求出两个Hash数组的值。比较两个Hash数组的值是否相同,就可以完美得到100分。至于原理是因为一个会有5%的冲突,但两个Hash就可以把冲突降到接近于0。
- 用set,可以比较稳健得到70分,但也不能满。
具体代码如下:
因博主是蒟蒻,所以写代码参考了一下,出题人给的标程。)
#include<cmath>#include<cstdio>const int maxm=200010;long long hash_a[maxm],hash_b[maxm];long long Hash_a[maxm],Hash_b[maxm];long long Hash_pow_a[maxm],Hash_pow_b[maxm];//指数数组int n,m,ans;char str[maxm];void Init(int p1,int P1,int p2,int P2){ for(int i=1;i<=n;i++) { Hash_a[i]=(1ll*Hash_a[i-1]*p1+(str[i]-'a'+1))%P1; Hash_pow_a[i]=1ll*Hash_pow_a[i-1]*p1%P1; Hash_b[i]=(1ll*Hash_b[i-1]*p2+(str[i]-'a'+1))%P2; Hash_pow_b[i]=1ll*Hash_pow_b[i-1]*p2%P2; }}int hash_(int l,int r,int p,int P,int k){ if(k==1) return (Hash_a[r]-1ll*Hash_a[l-1]*Hash_pow_a[r-l+1]%P+P)%P; return (Hash_b[r]-1ll*Hash_b[l-1]*Hash_pow_b[r-l+1]%P+P)%P;}void _qst(int l,int r)//快排,可以使用sort,开结构体 //根据HashA的值排序。{ int i,j,m,mm,t; i=l;j=r; m=hash_a[(i+j)>>1];//位运算,相当于除以2 mm=hash_b[(i+j)>>1]; while(i<=j) { while(hash_a[i]<m||(hash_a[i]==m&&hash_b[i]<mm))i++; while(hash_a[j]>m||(hash_a[j]==m&&hash_b[j]>mm))j--; if(i<=j) { t=hash_a[i];hash_a[i]=hash_a[j];hash_a[j]=t; t=hash_b[i];hash_b[i]=hash_b[j];hash_b[j]=t; i++;j--; } } if(i<r)_qst(i,r); if(l<j)_qst(l,j);}int main(){ scanf("%d%d",&n,&m); scanf("%s",str+1); Hash_pow_a[0]=1; Hash_pow_b[0]=1; Init(61,1000000007,97,1000000009); for(int i=1;i<=n-m+1;i++) { hash_a[i]=hash_(i,i+m-1,61,1000000007,1); hash_b[i]=hash_(i,i+m-1,97,1000000009,2); } _qst(1,n-m+1); for(int i=1;i<=n-m+1;i++) { if(hash_a[i]==hash_a[i-1]&&hash_b[i]==hash_b[i-1]) continue; ans++; } printf("%d",ans);}
- Hash更进一步(Hash字符串——BDKRHash)
- poj2503(字符串hash)
- Tyvj1057(字符串hash)
- boj408字符串——hash的应用
- 字符串hash——Codeforces533F Encoding
- 字符串hash
- 字符串HASH
- 字符串Hash
- 字符串hash
- 字符串hash
- 字符串hash
- 字符串Hash
- 字符串hash
- 字符串hash
- 字符串 HASH
- 字符串Hash
- 字符串hash
- 字符串hash
- 深入Hadoop之MapReduce
- node.js使用(一):安装与使用方法
- centos中iptables和firewall防火墙开启、关闭、查看状态、基本设置等
- JSP学习笔记
- java零散知识点记录
- Hash更进一步(Hash字符串——BDKRHash)
- 将输入的字符串转为char字符数组
- 我第一天的Python学习
- js学习笔记
- 生成对抗网络学习笔记5----DCGAN(unsupervised representation learning with deep convolutional generative adv)的实现
- 一些关于状压dp的杂七杂八的东西
- 【bzoj2190】【仪仗队】欧拉函数+线性筛(浅尝ACM-J)
- opencv中常用的非线性滤波器--中值滤波medianBlur() 和 双边滤波bilateralFilter()
- 记录我第一次写sql server 2005的存储过程