小可可是学校图书馆的管理员,现在他接手了一个十分棘手的任务。由于学校需要一些材料,校长需要在文章中检
索一些信息。校长一共给了小可可N篇文章,每篇文章为一个字符串。现在,校长需要他找到这样的单词,它至少
在这N篇文章中的M篇文章里出现过,且单词长度为L。可是,工作量十分庞大,但校长又急需小可可完成这项任务
。现在他向你求助,需要你编写程序完成这项艰巨的任务
Input
第1行3个正整数N,M,L,表示文章的数目,单词至少出现在M篇文章中和每个单词的长度。
接下来N行,每行一个字符串,表示一篇文章。
1≤N,M≤2000,L≤1000。每篇文章长度不大于1000,均有小写字母组成
Output
仅一行,表示满足检索条件的单词数。
Sample Input
3 2 2
noip
istudycpp
imacppstudent
Sample Output
5
//这5个单词分别为:st,tu,ud,pp,cp。
Sol:对于一些数据精心构造过的,最好写成双hash
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef long long LL;
const int MaxN=2005;
const int MaxM=1000005;
const int MinMod=999973;
const LL MaxMod=499999999999993ll;
struct Node
{
int no,cnt;//no为单词所在文章编号,cnt为单词出现的次数
LL s;//s为单词的hashh值
int next;//用开散列解决冲突
}h[MaxM];
int N,M,L,tot,ans;
int first[MaxM];
char str[MaxN][MaxN];
void add(int u,int x,LL s)
//将在第x篇文章中出现的短hashh值为u,长hashh值为s的单词加入hashh表
{
++tot;
h[tot].s=s;
h[tot].cnt=1;
h[tot].no=x;
h[tot].next=first[u];
first[u]=tot;
}
void hashh(int x,int u,LL s)
{int i;
for(i=first[u];i!=0;i=h[i].next)
if (s==h[i].s)//在hashh表出现过
{
if (h[i].no==x) return;
//也是在第x篇文章中出现,就不用管了
h[i].no=x;
h[i].cnt++;//出现的次数加1
return;
}
add(u,x,s);
}
void init()
{
int i;
scanf("%d%d%d",&N,&M,&L);
for(i=1;i<=N;i++)
scanf("%s",&str[i]);
ans=0;
}
void work()
{int i,j,u,k,k1;
LL s,k2;
k1=k2=1;
for(j=0;j<L-1;j++)
{
k1=k1*26%MinMod;//数量级
k2=k2*26%MaxMod;
}
for(i=1;i<=N;i++)
{
u=s=0;
for (j=0;j<L;j++)
{
u=(u*26+str[i][j])%MinMod;//短hashh值
s=(s*26+str[i][j])%MaxMod;//长hashh值
}
hashh(i,u,s);
k=strlen(str[i]);
for(j=L;j<k;j++)
{
u=((u-str[i][j-L]*k1)%MinMod+MinMod)%MinMod;//前面去一位后面加一位
s=((s-str[i][j-L]*k2)%MaxMod+MaxMod)%MaxMod;
u=(u*26+str[i][j])%MinMod;
s=(s*26+str[i][j])%MaxMod;
hashh(i,u,s);
}
}
}
void output()
{
int i;
for(i=1;i<=tot;i++)
if(h[i].cnt>=M) ++ans;
printf("%d
",ans);
}
int main(void)
{
init();
work();
output();
return 0;
}
单Hash的做法,事实上有很大可能出错的,某两个不同的字符串hash出来的值是一样的。
#include<bits/stdc++.h>
#define ll long long
#define base 31
using namespace std;
const int mod=1e9+7,maxm=2e6+10;
int n,m,l,ans;
int f[maxm],g[maxm];
ll p[1010]={1},hash1[maxm];
char s[1010];
inline int add(int x)
{
int tmp=x%maxm;
while(hash1[tmp]&&hash1[tmp]!=x)tmp=(tmp+1)%maxm;
return tmp;
}
int main()
{
scanf("%d%d%d",&n,&m,&l);
for(int i=1;i<l;i++)
p[i]=p[i-1]*base%mod;
while(n--)
{
scanf("%s",s+1);
int len=strlen(s+1);
ll sum=0;
for(int i=1;i<l;i++)
sum=(sum+p[l-1-i]*s[i])%mod;
for(int i=l;i<=len;i++)
{
sum=(sum+mod-p[l-1]*s[i-l]%mod)%mod;
sum=(sum*base+s[i])%mod;
int k=add(sum);
hash1[k]=sum;
if(g[k]!=n)
{
if(++f[k]==m)ans++;
g[k]=n;
}
}
}
printf("%d",ans);
return 0;
}