您的位置:首页 > 其它

【JZOJ 3870】单词检索

2017-01-16 22:42 309 查看

Description

小可可是学校图书馆的管理员,现在他接手了一个十分棘手的任务。

由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可N篇文章,每篇文章为一个字符串。现在,校长需要他找到这样的单词,它至少在这N篇文章中的M篇文章里出现过,且单词长度为L。可是,工作量十分庞大,但校长又急需小可可完成这项任务。

现在他向你求助,需要你编写程序完成这项艰巨的任务。

Solution

这题显然可以字符串哈希,

用两个哈希,枚举每一个串,再枚举开头,先看一下这个子串在当前的整个串中是不是第一次出现,再把它的哈希值加1,相应的,判断一下这个哈希值出现的次数是否等于M,

为了保险,建议使用双哈希,

复杂度:O(nm)

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int N=2200,mo=1e9+7,mo1=998244353;
const int moh=1564437;
int n,m,m1,ans;
int a
[N/2];
int nx
[N/2];
struct qqww{int a,b;};
int z[moh][3];
int Z[moh][2],z1[moh][2];
// map<int,qqww>z;
// map<int,int>z1,Z;
bool H1(int q,int w)
{
int i=q%moh;
while(Z[i][0]&&Z[i][0]!=q)i=(i+1)%moh;
Z[i][0]=q;
if(Z[i][1]<w){Z[i][1]=w;return 1;}
return 0;
}
int H(int q)
{
int i=q%moh;
while(z[i][0]&&z[i][0]!=q)i=(i+1)%moh;
return i;
}
int H2(int q)
{
int i=q%moh;
while(z1[i][0]&&z1[i][0]!=q)i=(i+1)%moh;
return i;
}
int main()
{
scanf("%d%d%d",&n,&m,&m1);
fo(i,1,n)
{
char ch=' ';
for(;ch>'z'||ch<'a';ch=getchar());
for(;ch>='a'&&ch<='z';ch=getchar())a[i][++a[i][0]]=ch-96;
}
ans=0;
LL q,w,q1,w1;
LL qn=576923081,wn=729486258;
int t;
fo(I,1,n)
{
q1=w1=1;q=w=0;
fo(i,1,m1-1)q=(q+(a[I][i]-1)*q1)%mo,w=(w+(a[I][i]-1)*w1)%mo1,q1=q1*26%mo,w1=w1*26%mo1;
fo(i,m1,a[I][0])
{
q=(q+(a[I][i]-1)*q1)%mo,w=(w+(a[I][i]-1)*w1)%mo1;
if(H1(q,I))
{
t=H(q);
if(z[t][2]==w||z[t][2]==0)
{
z[t][2]=w;
if((++z[t][1])==m)ans++;
}else
{
t=H2(w);
if((++z1[t][2])==m)ans++;
}
}
q=(q-a[I][i-m1+1]+1)*qn%mo;
w=(w-a[I][i-m1+1]+1)*wn%mo1;
}
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: