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值 ,
對於1-L位的hash值 ,
可以用 遞推出
#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;
}