传送门: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.
(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.
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.
3 3 abcabcbcaabc
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;
}