hdu-4821(BKDRHash字符串哈希)
2017-07-26 11:19
429 查看
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4821
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
Sample Output
题目大意:有一个字符串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;
}
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;
}
相关文章推荐
- HDU - 4821 I - String 字符串哈希(bkdrhash)+成段求值+map去重
- [字符串hash] hdu 4821 String
- HDU 4821 String 字符串hash(水
- HDU 4821 String 字符串哈希
- hdu 4821 String(枚举 + 字符串hash)
- HDU 4821 String(字符串hash)
- [HDU 4821] String (字符串哈希)
- HDU 4821 字符串哈希
- HDU 4821 String 字符串哈希
- HDU 4821 String 字符串HASH
- hdu 4821 String 字符串hash
- hdu 1800 字符串的hash(BKDRHash 模版)大牛推荐的函数
- HDU 4821 String(BKDRHash)
- HDU 4821 字符串hash
- [HDU 4821]String[字符串hash][存疑]
- 【字符串哈希】【BKDRhash】【Rabin-Karp算法】模板
- HDU 4821 String 字符串hash
- HDU 4821 String (字符串hash,技巧暴力)
- HDU 4821 String(字符串Hash)
- HDU 4821 String (2013长春现场赛I题) 字符串Hash