首页 > 代码库 > 【模板】字符串哈希

【模板】字符串哈希

题目描述

如题,给定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人数的话),我想你一定会明白字符串哈希的正确姿势的^_^

最朴素的hash,过了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更简单。

【模板】字符串哈希