题解 P3370 【【模板】字符串哈希】
Starlight237 · · 题解
ELF\ Hash
我们先看一个最简单的错位叠加哈希:
inline uint hs(char *s){
reg uint sm=0;
reg char *p=s;
while(*p)sm=(sm<<4)+*p++;
return (sm&0x7fffffff);
}
但是这个哈希函数显然可能会溢出,从而增加冲突的可能性。
为了防止溢出,可以利用一个辅助变量x,每次更新哈希值的时候执行以下操作:
(x=sm&0xf0000000)&&(sm^=(x>>24),sm&=~x);
//为了压行+卡常数进行了改写,实际上等同如下代码:
x=sm;
if(x&0xf0000000)sm^=(x>>24),sm&=~x;
它的意义是:取x的可能溢出的最高一位,若不为零则有溢出风险,这时最简单的方式就是直接暴力地把溢出的内容转移到低位,这样既可保证每一位都对hash值有影响。
可以证明,这样的哈希方式正确率是极高的。
#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef unsigned int uint;
uint hsh[10001],ans=1,n;
static char str[10001];
inline uint hs(char *s){
reg uint sm=0,x=0;
reg char *p=s;
while(*p)
sm=(sm<<4)+*p,
(x=sm&0xf0000000)&&(sm^=(x>>24),sm&=~x),
++p;
return (sm&0x7fffffff);
}
int main(){
freopen("1.in","r",stdin);
scanf("%d",&n);
for(reg int i=1;i<=n;++i)
scanf("%s",str),hsh[i]=hs(str);
sort(hsh+1,hsh+n+1);
for(reg int i=1;i<n;++i)
ans+=hsh[i]!=hsh[i+1];
printf("%d",ans);
return 0;
}