【模板】字符串哈希

时间:2023-01-07 15:48:25

题目描述

如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字、大小写字母,大小写敏感),请求出N个字符串*有多少个不同的字符串。

友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转PJ试炼场:)

输入输出格式

输入格式:

 

第一行包含一个整数N,为字符串的个数。

接下来N行每行包含一个字符串,为所提供的字符串。

 

输出格式:

 

输出包含一行,包含一个整数,为不同的字符串个数。

 

输入输出样例

输入样例#1:
5
abc
aaaa
abc
abcc
12345
输出样例#1:
4

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,Mi≈6,Mmax<=15;

对于70%的数据:N<=1000,Mi≈100,Mmax<=150

对于100%的数据:N<=10000,Mi≈1000,Mmax<=1500

样例说明:

样例中第一个字符串(abc)和第三个字符串(abc)是一样的,所以所提供字符串的集合为{aaaa,abc,abcc,12345},故共计4个不同的字符串。

Tip: 感兴趣的话,你们可以先看一看以下三题:

BZOJ3097:http://www.lydsy.com/JudgeOnline/problem.php?id=3097

BZOJ3098:http://www.lydsy.com/JudgeOnline/problem.php?id=3098

BZOJ3099:http://www.lydsy.com/JudgeOnline/problem.php?id=3099

如果你仔细研究过了(或者至少仔细看过AC人数的话),我想你一定会明白字符串哈希的正确姿势的^_^

最朴素的字符串转化,过了80分。

代码:

 1 #include<cstdio>
2 #include<cstring>
3 using namespace std;
4 const int mod=88782431;
5 int n,l,ans;
6 unsigned int hash;
7 bool v[90000000];
8 char ch[3000];
9 int main(){
10 scanf("%d",&n);
11 for(int i=1;i<=n;i++){
12 scanf("%s",&ch);
13 l=strlen(ch);hash=1;
14 for(int j=0;j<l;j++){
15 hash=(hash*ch[j]*2351)%mod;
16 }
17 if(!v[hash]){
18 v[hash]=1;
19 ++ans;
20 }
21 }
22 printf("%d\n",ans);
23 return 0;
24 }

结果:

#1AC2ms/102238kB #2AC3ms/102238kB#3AC2ms/19226kB#4AC16ms/102238kB

#5AC17ms/83347kB#6AC17ms/83316kB#7AC13ms/102238kB

#8WA122ms/102238kB//错误的答案。得分0 On line 1 column 3, read 19, expected 20.

 

#9WA122ms/102238kB//错误的答案。得分0 On line 1 column 4, read 1, expected 2.

#10AC122ms/102238kB

用稍正经点的hash就行。

代码实现:

 1 #include<cstdio>
2 #include<cstring>
3 using namespace std;
4 const int mod=29989;
5 unsigned int hash;
6 int n,l,a,b,ans,v[30000];
7 int id[10010][1510];
8 char ch[1510];
9 bool bj(int x,int y){
10 if(id[x][0]!=id[y][0]) return 0;
11 for(int i=id[x][0];i>id[y][0]-5;i--)//比较五个就行,多了用时多,恩,其实比较最后一个了之后再比较长度和随机一个(稍靠后)应该就行了。
12 if(id[x][i]!=id[y][i]) return 0;
13 return 1;
14 }
15 int main(){
16 scanf("%d",&n);
17 for(int i=1;i<=n;i++){
18 scanf("%s",&ch);
19 id[i][0]=strlen(ch);hash=1;
20 for(int j=0;j<id[i][0];j++){
21 hash=(hash*ch[j]*13)%mod;
22 id[i][j+1]=hash;//把求hash的中间值存一下,其实也不用存这么多。
23 }
24 while(v[hash]){//如果hash值一样,看看字符串是否相同。
25 if(bj(v[hash],i)) break;
26 hash++;
27 }
28 if(!v[hash]){//如果这个字符串未出现过,就放下。
29 v[hash]=i;
30 ++ans;
31 }
32 }
33 printf("%d\n",ans);
34 return 0;
35 }

hash模板题,当然用set或者map更简单。我之所以不用,是为了给出题人个面子。(其实不会用Orz)

题目来源:洛谷