Poj 1200 Crazy Search(字符串Hash)

Poj 1200

题意:给你一个n和m以及一个有m个不同字母组成的字符串,问有多少个长度为n的不同字符子串;

题解:以m为进制进行Hash。虽然是看了解题报告才会的但必须要理解并且学会运用:https://www.cnblogs.com/gj-Acit/archive/2013/05/15/3080734.html

#include<cstring>//别用set,set的添加是红黑树实现时间复杂度是O(logN),在这里会超时
#include<cstdio>
#define ull unsigned long long
using namespace std;
const int N=1e7+6e6+5;
using namespace std;
int p[N];
int len;
char str[N];
bool hash_[N];
int main(){
    int n,m;
    scanf("%d %d %s",&n,&m,str+1);
    len=strlen(str+1);
    int j=0;
    for(int i=1;i<=len;i++){
        if(!p[str[i]])p[str[i]]=++j;//以m为进制数,将各个字母分别用数字表示进行hash
        if(j==m)break;
    }
    ull Base=1;
    ull Hash=0;
    for(int i=1;i<=n;i++){//首先将前n个数将m进制转换为10进制
        Hash=Hash*m+p[str[i]]-1;//减一是为了因为m进制数为0到m-1
        Base*=m;
    }
    Base/=m;
    hash_[Hash]=1;
    int ans=1;
    for(int i=2;i+n<=len+1;i++){
        Hash=(Hash-(p[str[i-1]]-1)*Base)*m+p[str[i+n-1]]-1;//原Hash减去子串首字母代表的数乘以Base得到的是剩下字母所生成的10进制数那么再乘以一个m在加上新进的一个字母所代表的数,得到的是新子串所代表的10进制数(即其hash值)
        if(!hash_[Hash]){
            hash_[Hash]=1;
            ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-02-06 21:57  采蘑菇的小西佬  阅读(146)  评论(0编辑  收藏  举报