您的位置:首页 > 其它

hdu-4821(BKDRHash字符串哈希)

2017-07-26 11:19 429 查看
传送门: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.

InputThe 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.
OutputFor each test case, output the answer in a single line.
Sample Input
3 3
abcabcbcaabc


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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: