[模板]字符串哈希的简易做法

题目描述

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

 

 

Solution:

首先你得会写链式前向星(即链表/邻接表,常用于存储图)。将一个字符串看成255进制数,然后把它转成十进制数,并找一个大质数对该十进制数取模。这里你也可以使用秦九韶算法(很简单,可以百度,名字高端了一点;如果不会你怎么转的k到10进制就怎么转233),就能获得这个字符串的哈希值了。

然后如何判重?两个字符串的哈希值相同就证明这两个字符串相同——原本应该是这样的。但由于取模,确实可能出现两个字符串hash值出现重复的情况。这时我们就需要套个邻接表,给每个哈希值下的字符串都判断一遍。如果没有字符串相同,再往这个哈希值下插入这个字符串,并计数加一。事实证明,哈希值冲突的情况不多,如果链式前向星写得熟那更是万无一失。Luogu评测耗时为500ms左右,比很多评测记录还是快很多。如果只是一般的Hash,我觉得用这个基本上就够了的说....=、=想办法把要记录的状态转成k进制数,再转成10进制数对大质数取模,然后套进邻接表来判重。代码复杂度不高,而且效率也不差。

怎么把字符串在邻接表里套进同一哈希值?嗯....你把它看作图论里的插边。我觉得这两种东西差不多。

所谓的大质数....嗯嗯,我不管那么多的,我直接1000013就做了。如果想要靠谱一点的大质数....百度哇。

下面是代码。

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e6+13,N=10010;

int h[MOD],nexp[N],p=1;
string s[N];//链式前向星 

int getHash(string x){
    int plus=255,ret=x[0],len=x.size();
    for(int i=1;i<len;i++){
        ret=(ret*plus)%MOD;
        ret+=x[i];
    }
    return ret%MOD;
}//获取字符串的哈希值 
bool insHash(string x){
    int c=getHash(x);
    for(int u=h[c];u;u=nexp[u]){
        if(s[u]==x)return 0;//若发现重复则返回0 
    }
    nexp[p]=h[c],h[c]=p,s[p]=x,p++;
    return 1;//否则插入 
}


int main(){
    std::ios::sync_with_stdio(false); //相关内容可以百度搜索,可以加快cin效率 
    int n;
    cin>>n;
    string a;
    int ans=0;
    for(int i=0;i<n;i++){
        cin>>a;
        if(insHash(a))ans++;
    }
    cout<<ans;
    return 0;
}

 

posted @ 2017-07-29 08:52  NagaseIori  阅读(2663)  评论(0编辑  收藏  举报