最简单的Hash思想就是建立一个大于等于值域的数组进行统计和映射
主要操作:
1.计算Hash函数的值
2.定位到对应链表中依次遍历、比较
一般是大数%一个较大的质数,如算阶上给的公式:
H(x)=(x%P)+1;
这是最常用的,P就是一个很大的质数,因此我们平时要记着几个大的质数,如99991,131,13331,有些数据量比较大且不考高精的题让%的大多也是质数。
记得有道题好像%的不是质数所以输出0就能40分,但据说河南没人想出来这么做
还有:
1.直接定址法:H(x)=x或H(x)=a*x+b
2.数字分析法:取关键字的若干位组成哈希地址
3.平方取中法:关键字平方后取中间几位
4.折叠法:将关键数字分割成位数的及部分,取叠加和作为哈希地址
5.伪随机数法:先生成随机数序列r[N],然后H(x)=r[x]
Hash主要是把复杂的信息映射到一个容易被维护的值域里,而值域变小就很容易造成冲突。
所以Hash很重要的一个步骤就是得解决冲突。
鄙人主要在伟人的书2中看到以下两种做法:
1.拉链法
相同的地址关键字值均链入对应列表中
2.线性探测法
为冲突的关键字找到新的哈希地址
再来看道板子题
题目描述
很久很久以前,森林里住着一群兔子。有一天,兔子们想要研究自己的 DNA 序列。我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母),然后我们每次选择两个区间,询问如果用两个区间里的 DNA 序列分别生产出来两只兔子,这两个兔子是否一模一样。注意两个兔子一模一样只可能是他们的 DNA 序列一模一样
输入和输出
Input
第一行一个 DNA 字符串 S。 接下来一个数字 m,表示 m 次询问。 接下来 m 行,每行四个数字 l1, r1, l2, r2,分别表示此次询问的两个区间,注意字符串的位置从1开始编号。 其中 1 ≤ length(S), m ≤ 1000000
Output
对于每次询问,输出一行表示结果。如果两只兔子完全相同输出 Yes,否则输出 No(注意大小写)
样例
Sample Input
aabbaabb
3
1 3 5 7
1 3 6 8
1 2 1 2
Sample Output
Yes
No
Yes
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char s[N];
unsigned long long rabbita,rabbitb,n,t,f[N],p[N],l1,r1,l2,r2;
int main()
{
scanf("%s",s+1);
n=strlen(s+1),p[0]=1;
cin>>t;
for(int i=1;i<=n;i++)
{
f[i]=f[i-1]*131+(s[i]-'a'+1);
p[i]=p[i-1]*131;
}
for(int i=1;i<=t;i++)
{
scanf("%lld%lld%lld%lld",&l1,&r1,&l2,&r2);
rabbita=f[r1]-f[l1-1]*p[r1-l1+1];
rabbitb=f[r2]-f[l2-1]*p[r2-l2+1];
if(rabbita==rabbitb) puts("Yes");
else puts("No");
}
return 0;
}
这个用无符号long long记录,爆掉就爆掉吧,反正无符号时没有负数,爆了之后还是整数
但是这个数据量大得感人,用cout会超时,得用puts,而puts还自带换行很方便。