1. 单词检索
(search.pas/c/cpp)
【问题描述】
小可可是学校图书馆的管理员,现在他接手了一个十分棘手的任务。
由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可N篇文章,每篇文章为一个字符串。现在,校长需要他找到这样的单词,它至少在这N篇文章中的M篇文章里出现过,且单词长度为L。可是,工作量十分庞大,但校长又急需小可可完成这项任务。
现在他向你求助,需要你编写程序完成这项艰巨的任务。
【输入格式】
第1行3个正整数N,M,L,表示文章的数目,单词至少出现在M篇文章中和每个单词的长度。
接下来N行,每行一个字符串,表示一篇文章。
【输出格式】
仅一行,表示满足检索条件的单词数。
【样例】
search.in search.out
3 2 2
noip
istudycpp
imacppstudent 5
【样例解释】
这5个单词分别为:st,tu,ud,pp,cp。
【数据范围】
对于20%的数据有1≤N,M≤10;
对于60%的数据有1≤N,M≤100;
对于100%的数据有1≤N,M≤2000,L≤1000。每篇文章长度不大于1000,均有小写字母组成。
三重哈希,对于一篇文章,先算出0-L-1位的hash值 xx,
对于1-L位的hash值yy,
可以用xx递推出
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
using namespace std;
const int p1=29,p2=37,p3=41;
const ll Mod1=10003,Mod2=1000007,Mod3=1000009; //这里用了三重hash,其实对拍出来有数据可以卡掉,Mod3应该取
//大一点,如998244353
struct Node {
int a,b,c;
};
int n,m,l;
vector<Node> a[Mod1+10],A[Mod1+10]; //比较懒的我打了vector实现hash表
char s[1010];
ll s1,s2,s3;
inline bool se(int x,int y,int z) {
for(register unsigned int i=0;i<A[x].size();i++) {
if(A[x][i].a==y && A[x][i].b==z) {
return true;
}
}
return false;
}
inline void inse(int x,int y,int z) {
for(register unsigned int i=0;i<a[x].size();i++) {
if(a[x][i].a==y && a[x][i].b==z) {
a[x][i].c++;
return;
}
}
a[x].push_back((Node){y,z,1});
}
inline void Inse(int x,int y,int z) {
for(register unsigned int i=0;i<A[x].size();i++) {
if(A[x][i].a==y && A[x][i].b==z) {
A[x][i].c++;
return;
}
}
A[x].push_back((Node){y,z,1});
}
int main()
{
freopen("search.in","r",stdin);
freopen("search.out","w",stdout);
scanf("%d%d%d",&n,&m,&l);
long long o1=1,o2=1,o3=1;
for(int i=1;i<=l-1;i++) {
o1=(o1*p1)%Mod1;
o2=(o2*p2)%Mod2;
o3=(o3*p3)%Mod3;
}
for(int j=1;j<=n;j++) {
for(register int i=0;i<Mod1;i++) {
A[i].clear();
}
scanf("%s",s);
int len=strlen(s);
if(len<l) continue;
s1=s2=s3=0;
for(int i=0;i<l;i++) {
s1=(s1*p1+s[i])%Mod1;
s2=(s2*p2+s[i])%Mod2;
s3=(s3*p3+s[i])%Mod3;
}
if(!se(s1,s2,s3)) inse(s1,s2,s3);
Inse(s1,s2,s3);
// if(s1==9271) {
// printf("%d %d\n",j,0);
// }
for(int i=1;i<len-l+1;i++) {
s1=(s1-s[i-1]*o1+s[i-1]*Mod1)%Mod1;
s1=(s1*p1+s[i+l-1])%Mod1;
s2=(s2-s[i-1]*o2+s[i-1]*Mod2)%Mod2;
s2=(s2*p2+s[i+l-1])%Mod2;
s3=(s3-s[i-1]*o3+s[i-1]*Mod3)%Mod3;
s3=(s3*p3+s[i+l-1])%Mod3;
if(!se(s1,s2,s3)) inse(s1,s2,s3);
Inse(s1,s2,s3);
// if(s1==7386) {
// printf("%d %d\n",j,i);
// }
}
}
int acht=0;
for(int i=0;i<Mod1;i++) {
for(register unsigned int j=0;j<a[i].size();j++) {
if(a[i][j].c>=m) {
acht++;
// printf("%d %d %d %d\n",i,a[i][j].a,a[i][j].b,a[i][j].c);
}
}
}
printf("%d\n",acht);
return 0;
}