【笔记】哈希,Hash

将字符串(或是其他东西)映射到一个更容易“操作”的集合里,根据所需“操作”决定方式。
思考的话,比如考虑必要条件,然后多几个不同哈希意义的必要条件就能苛刻出大概率的充分条件。

一个常用手段是利用 unsigned long long 的自然溢出,可加可减都方便。
不过...多模哈希的话你tm要换模数啊!!!你只换底数有什么用
1311e9+71e9+919260817

区分字符串:

类似进制的做法,取一个质数作为 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为循环节
结论:一个字符串的所有循环节的长度,均是其最短循环节长度的倍数

posted @ 2021-02-18 22:08  zrkc  阅读(61)  评论(0)    收藏  举报