【笔记】哈希,Hash
将字符串(或是其他东西)映射到一个更容易“操作”的集合里,根据所需“操作”决定方式。
思考的话,比如考虑必要条件,然后多几个不同哈希意义的必要条件就能苛刻出大概率的充分条件。
一个常用手段是利用 unsigned long long 的自然溢出,可加可减都方便。
不过...多模哈希的话你tm要换模数啊!!!你只换底数有什么用
131;1e9+7,1e9+9,19260817
区分字符串:
类似进制的做法,取一个质数作为 base ,再取一个质数作为模数。显然多模哈希更不容易冲突,另外用 ull 自然溢出更方便。212370440130137957ll 是质数。
for (int i=0; i< len; i++) h = h * base + (ull)s[i];
区分字符集:
比如 {a, a, b, c} 、 {a, c} 这种,一种做法是多维数。考虑:两个字符集相同,则各字母哈希值之和相同,那就多几维哈希:
for (int i=0; i< MAXN; i++) {
for (int j=0; j< MAXD; j++) {
ha[i].d[j] = rad();
}
}
可以利用 ull 的自然溢出,更方便:
void add(dim &a, dim b)
{
for (int i=0; i< MAXD; i++) a.d[i] += b.d[i];
}
void del(dim &a, dim b)
{
for (int i=0; i< MAXD; i++) a.d[i] -= b.d[i]; // 想想看,不也是可减的吗
}
int cmp(dim a, dim b)
{
for (int i=0; i< MAXD; i++) if (a.d[i] != b.d[i]) return 0;
return 1;
}
例题:luogup5270
多个关键字:
哈希成 \(a\times 1e15+b\times 1e10+c\times 1e5+d\) 这种,就可以自然地排序了,或者拿去用数据结构维护。
例题:[HNOI2005]虚拟内存
循环子串:
基于调和级数的哈希 1+1/2+1/3+...+1/N = logN ,直接枚举判断,虽然带个 log 不过用途肯定不止这个
哈希 O(1) 判断某一个长度 x 是否为循环节:若 S[x+1...n] == S[1...n-x] ,则x为循环节
结论:一个字符串的所有循环节的长度,均是其最短循环节长度的倍数

ull 真好用
浙公网安备 33010602011771号