單詞檢索題解

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=pL1s0+pL2s1+...+p0sL1
對於1-L位的hash值y ,y=pL1s1+pL2s2+...+p0sL
可以用x 遞推出y

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章