Description
小可可是学校图书馆的管理员,现在他接手了一个十分棘手的任务。
由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可N篇文章,每篇文章为一个字符串。现在,校长需要他找到这样的单词,它至少在这N篇文章中的M篇文章里出现过,且单词长度为L。可是,工作量十分庞大,但校长又急需小可可完成这项任务。
现在他向你求助,需要你编写程序完成这项艰巨的任务。
Input
第1行3个正整数N,M,L,表示文章的数目,单词至少出现在M篇文章中和每个单词的长度。
接下来N行,每行一个字符串,表示一篇文章。
Output
仅一行,表示满足检索条件的单词数。
Sample Input
3 2 2
noip
istudycpp
imacppstudent
Sample Output
5
【样例解释】
这5个单词分别为:st,tu,ud,pp,cp。
Data Constraint
对于20%的数据有
1≤N,M≤10
;
对于60%的数据有
1≤N,M≤100
;
对于100%的数据有
1≤N,M≤2000,L≤1000
。每篇文章长度不大于1000,均有小
写字母组成。
Solution
这题是典型的 字符串Hash ,开散列。
先枚举每篇文章,在枚举其中的每个单词,把单词转换成模意义下26进制,质数取 109+7 。
之后把这个数放进 Hash 表中,判断是否存在,达到m次即答案+1,上限取 2∗106 。
枚举过程中注意边加边判断,总时间复杂度为 O(N∗(N−L)) !
Code
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1002,M=N*N*2,mo=1e9+7;
int n,m,l,ans;
int f[M],g[M];
long long p[N],h[M];
char s[N];
inline int hash(int x)
{
int y=x%M;
while(h[y] && h[y]!=x) y=(y+1)%M;
return y;
}
int main()
{
scanf("%d%d%d",&n,&m,&l);
for(int i=p[0]=1;i<l;i++) p[i]=p[i-1]*26%mo;
n++;
while(--n)
{
scanf("%s",s+1);
int len=strlen(s+1);
long long sum=0;
for(int i=1;i<l;i++) sum=(sum+p[l-1-i]*s[i])%mo;
for(int i=l;i<=len;i++)
{
sum=(sum+mo-p[l-1]*s[i-l]%mo)%mo;
sum=(sum*26+s[i])%mo;
int k=hash(sum);
h[k]=sum;
if(g[k]!=n)
{
if(++f[k]==m) ans++;
g[k]=n;
}
}
}
printf("%d",ans);
return 0;
}