单词检索【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);
} 

这里写图片描述

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