Hash算法
H a s h Hash Hash算法,个人的理解是将若干个不方便表示的数(如数据过大等),通过一个特定的函数将其转化为方便表示的数,在此基础上进行操作。
详细概念如下:百度百科
比如,如果数据量过大,无法开桶进行统计(其实桶计数就是函数
y
=
x
y=x
y=x),那么可以将每一个数都
m
o
d
mod
mod一个质数(
m
o
d
mod
mod质数的原因是减小冲突),用模得的数代表原数。
再比如,字符串
H
a
s
h
Hash
Hash中,将每一个字符串进行
H
a
s
h
Hash
Hash处理,就可以用一个数来代表一个字符串,通过这个数来对字符串进行操作、判断。
具体细节操作请自行学习
例题1
Snowflake Snow Snowflakes
时间限制:4s 空间限制:64MB
题目描述
您可能听说没有两个雪花是相似的。 你的任务是编写一个程序来确定这是否真的如此。 您的程序将读取有关雪花集合的信息,并搜索可能相同的一对。 每个雪花都有六个手臂。 对于每个雪花,您的程序将提供六个臂中每个臂的长度的测量。 任何具有相同长度相应臂的雪花都应该被程序标记为可能相同。
输入格式
第一行输入将包含一个整数n,0 n 100000,要遵循的雪花数量。 接下来是n行,每行描述一个雪花。 每个雪花将由包含六个整数的线(每个整数至少为0且小于10000000)描述,雪的长度为ake。 臂的长度将围绕雪花顺序给出(顺时针或逆时针),但它们可以从六个臂中的任何一个开始。 例如,相同的雪花可以描述为1 2 3 4 5 6或4 3 2 1 6 5。
输出格式
如果所有雪花都不同,您的程序应该打印消息: No two snowflakes are alike. 如果有一对可能相同的雪花,您的程序应该打印消息: Twin snowflakes found.
样例数据
input
2
output
1 2 3 4 5 6
4 3 2 1 6 5
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n;
const int pri=99991;
int sum,mul;
bool flag;
int val;
int head[110000];
int nxt[110000];
int tot;
int snow[110000][6];
int gethash(int *a)
{
sum=0;mul=1;
for(int i=0;i<6;i++)
{
sum=(sum+a[i])%pri;
mul=(long long)mul*a[i]%pri;
}
return (sum+mul)%pri;
}
bool equal(int *a,int *b)
{
for(int i=0;i<6;i++)
{
for(int j=0;j<6;j++)
{
flag=1;
for(int k=0;k<6;k++)
{
if(a[(i+k)%6]!=b[(j+k)%6])
{
flag=0;
}
}
if(flag==1)
{
return 1;
}
flag=1;
for(int k=0;k<6;k++)
{
if(a[(i+k)%6]!=b[(j-k+6)%6])
{
flag=0;
}
}
if(flag==1)
{
return 1;
}
}
}
return 0;
}
bool check(int *a)
{
val=gethash(a);
for(int i=head[val];i;i=nxt[i])
{
if(equal(snow[i],a))
{
return 1;
}
}
++tot;
memcpy(snow[tot],a,6*sizeof(int));
nxt[tot]=head[val];
head[val]=tot;
return 0;
}
void init()
{
cin>>n;
}
int main()
{
init();
for(int i=1;i<=n;i++)
{
int a[10];
for(int j=0;j<6;j++)
{
cin>>a[j];
}
if(check(a))
{
cout<<"Twin snowflakes found.";
return 0;
}
}
cout<<"No two snowflakes are alike.";
return 0;
}
例题2(字符串 h a s h hash hash)
兔子与兔子
题目描述
很久很久以前,森林里住着一群兔子。有一天,兔子们想要研究自己的 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(注意大小写)
样例数据
输入
aabbaabb
3
1 3 5 7
1 3 6 8
1 2 1 2
输出
Yes
No
Yes
代码如下:
#include<bits/stdc++.h>
using namespace std;
int qr()
{
int x=0,flag=0;char ch=0;
while(!isdigit(ch)) {flag|=ch=='-';ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return flag? -x:x;
}
string s;
int m;
unsigned long long f[1100000];
unsigned long long pri[1100000];
const int upri=13331;
int l1,r1,l2,r2;
char ch[1100000];
int len;
void init()
{
getline(cin,s);
len=s.size();
for(int i=1;i<=len;i++)
{
ch[i]=s[i-1];
}
}
void work()
{
pri[0]=1;
for(int i=1;i<=len;i++)
{
f[i]=f[i-1]*upri+(ch[i]-'a'+1);
pri[i]=pri[i-1]*upri;
}
}
void print()
{
m=qr();
for(int i=1;i<=m;i++)
{
l1=qr();r1=qr();l2=qr();r2=qr();
int pp=f[r1]-f[l1-1]*pri[r1-l1+1];
int qq=f[r2]-f[l2-1]*pri[r2-l2+1];
if(pp==qq)
{
puts("Yes");
}
else puts("No");
}
}
int main()
{
init();
work();
print();
}