【JZOJ 3870】单词检索

来源:互联网 发布:网络用语奶是什么意思 编辑:程序博客网 时间:2024/05/21 22:58

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][N/2];int nx[N][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;}
0 0
原创粉丝点击