hdu-4821(BKDRHash字符串哈希)

来源:互联网 发布:大学生java培训机构 编辑:程序博客网 时间:2024/04/29 05:31

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4821

                                                                

String

 

Given a string S and two integers L and M, we consider a substring of S as “recoverable” if and only if 
  (i) It is of length M*L; 
  (ii) It can be constructed by concatenating M “diversified” substrings of S, where each of these substrings has length L; two strings are considered as “diversified” if they don’t have the same character for every position. 

Two substrings of S are considered as “different” if they are cut from different part of S. For example, string "aa" has 3 different substrings "aa", "a" and "a". 

Your task is to calculate the number of different “recoverable” substrings of S.
Input
The input contains multiple test cases, proceeding to the End of File. 

The first line of each test case has two space-separated integers M and L. 

The second ine of each test case has a string S, which consists of only lowercase letters. 

The length of S is not larger than 10^5, and 1 ≤ M * L ≤ the length of S.
Output
For each test case, output the answer in a single line.
Sample Input
3 3abcabcbcaabc
Sample Output
2

题目大意:有一个字符串s,问有几个满足如下条件的子串:

1、子串的长度为m*L

2、这m个长为L的子子串各个不相等

     基本思路:

用BKDRHash的哈希方法求出字符串的哈希值,然后剩下的就查找有几个满足条件的子串就行了,在记录其中一个m*L的子串时,用map记录有多少不同的长为L的子子串。

#include <iostream>#include <cstring>#include <cmath>#include <cstdlib>#include <algorithm>#include <cstdio>#include <map>using namespace std;typedef unsigned long long LL;///无符号形长整数溢出时自动取模const int MAX=1e5+7,seed=31;char s[MAX];LL base[MAX],h[MAX];map<LL,int>mp;LL BKDRHash(int l,int r)///这是求每个子串的哈希值的方法{    return h[r]-h[l-1]*base[r-l+1];}int main(){    int m,l;    base[0]=1;    for(int i=1;i<=MAX;i++)base[i]=base[i-1]*seed;///基数    while(~scanf("%d%d",&m,&l))    {        int ans=0;        scanf("%s",s+1);        int len=strlen(s+1);        h[0]=0;        for(int i=1;i<=len;i++)            h[i]=h[i-1]*seed+s[i]-'a';///对整个字符串求哈希值        ///下面通过map来记录充计有多少对符合条件的m*l长度的字符串,个人感觉这里类似于尺取法        for(int i=1;i<=l&&i+m*l-1<=len;i++)///从i开始连续的m*l长度的子串,注意i<=l跳出循环(因为当i==l时,之后的情况都已经查询了)        {            mp.clear();            for(int j=i;j<=i+m*l-1;j+=l)            {                LL x=BKDRHash(j,j+l-1);                mp[x]++;            }            if(mp.size()==m)ans++;            for(int j=i+m*l;j+l-1<=len;j+=l)            {                LL x=BKDRHash(j,j+l-1);                mp[x]++;                LL y=BKDRHash(j-m*l,j-m*l+l-1);                mp[y]--;                if(mp[y]==0)mp.erase(y);                if(mp.size()==m)ans++;            }        }        printf("%d\n",ans);    }    return 0;}

原创粉丝点击