單詞檢索【NOIP2014八校聯考第4場第1試10.19】

題目

小可可是學校圖書館的管理員,現在他接手了一個十分棘手的任務。
由於學校需要一些材料,校長需要在文章中檢索一些信息。校長一共給了小可可N篇文章,每篇文章爲一個字符串。現在,校長需要他找到這樣的單詞,它至少在這N篇文章中的M篇文章裏出現過,且單詞長度爲L。可是,工作量十分龐大,但校長又急需小可可完成這項任務。
現在他向你求助,需要你編寫程序完成這項艱鉅的任務。

樣例輸入:
第1行3個正整數N,M,L,表示文章的數目,單詞至少出現在M篇文章中和每個單詞的長度。
接下來N行,每行一個字符串,表示一篇文章。
3 2 2
noip
istudycpp
imacppstudent

樣例輸出:
僅一行,表示滿足檢索條件的單詞數
5

數據範圍:
對於20%的數據有1≤N,M≤10;
對於60%的數據有1≤N,M≤100;
對於100%的數據有1≤N,M≤2000,L≤1000。每篇文章長度不大於1000,均有小寫字母組成。


剖解題目

給n個字符串,問至少在m個字符串裏出現過長度爲l的字符串額個數


思路

一開始就想到hash,但堅定的相信這是水法。。。
雖然最終真的是水法


解法

20%:神奇的暴力。
60%:更神奇的暴力。n^2+kmp。
100%:
1.後綴數組,但是不會。。
2.強行hash。
開一個較大的素數(要有與素數的緣分),3千萬左右。
當然,有爆空間的危險。。。。。。(原來有350M左右)。
爲了卡空間,改數據類型(一個數組改成short int後少50M),還把hash值再取模後改成short int的型,總算是卡到200M了。。。。


代碼

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define ll long long

using namespace std;

const int maxn=2005;
const ll mo=28282789,moo=31153;
short int ha[mo+5],n,m,len,bo[mo+5],id;
short int ha2[mo+5];
ll tmp[1005];
ll ans;
char s[maxn];
bool bz[mo+10];

int hash(ll x)
{
    ll y=x%mo;
    while (ha[y]!=x%moo&&ha[y]) y=y%mo+1;
    if (!ha[y]) ha[y]=x%moo; 
    if (bo[x]<id) ha2[y]++,bo[x]=id;
    return y;
}
int main()
{
    freopen("T.in","r",stdin);
    scanf("%d%d%d",&n,&m,&len);
    tmp[len]=1;
    for(int i=len-1;i>=1;i--) tmp[i]=tmp[i+1]*26%mo;
    fo(i,1,n){
        scanf("%s",s+1);
        int nowlen=strlen(s+1);
        if(nowlen<len) continue;
        ll value=0;
        id++;
        fo(i,1,len)
            value=(value+tmp[i]*s[i])%mo;

        int x=hash(value);
        if (ha2[x]>=m&&!bz[x]) ++ans,bz[x]=true;

        fo(i,len+1,nowlen){
            int pre=i-len;
            value=(((value-s[pre]*tmp[1])%mo+mo)%mo*26+s[i])%mo;

            x=hash(value);
            if (ha2[x]>=m&&!bz[x]) ++ans,bz[x]=true;
        }
    }
    printf("%lld\n",ans);
} 

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章