P3370 【模板】字符串哈希

2023-01-02

题目介绍

传送门

Hash详解

具体而言,你可以将hash理解为一个进制(奇怪的比喻

我们日常生活中常用的十进制是逢十进一。

比如,114514可以这样表示:

\[1 \times 10^5 + 1 \times 10^4 + 4 \times 10^3 + 5 \times 10^2 + 1 \times 10^1 + 4 \times 10^0\]

十进制的底数为 $10$ ,也就是说 $base = 10$ 。相应地,二进制的 $base = 2$, 十六进制的 $base = 16$ 。

于是乎,一个以 $base$ 作为底数的进制可以写作:

\[a_i \times base^{i-1} + a_{i-1} \times base^{i-2} + \cdots + a_1 \times base^0\]

好!非常好!CSP-J初赛内容你已经掌握了!

(没有听懂的话建议去搞P1017P1143

Hash就是对于字符串的每一位,找到对应的值。

我们以abcd为例:

$Hash(abcd)$

$=~’a’ \times base^3 + ~’b’ \times base^2 + ~’c’ \times base^1 + ~’d’ \times base^0$

其中, $base$ 是一个你自己定的值(推荐 $base$ 为质数,减少不同字符串却有相同 $base$ 值的可能)

Code

#include <bits/stdc++.h>
using namespace std;
/*数据类型选择 unsigned long long 自然溢出(虽然不是最好的方法)*/
const unsigned long long base = 131;  //设置base
string a[10005];
set <unsigned long long> hsh;
//set 这个数据结构是自动去重的
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		unsigned long long tmp = 0;
		for (int j = 0; j < a[i].length(); j++) {
			tmp = tmp * base + a[i][j];
        		//找到字符串的哈希值
		}
		hsh.insert(tmp);  //将这个哈希值存进 set
	}
	cout << hsh.size();
    	//set 的大小就是哈希值的数量,也就是不同字符串的数量
	return 0;
}