您的位置:首页 > 其它

单词检索【NOIP2014八校联考第4场第1试10.19】

2017-01-16 22:00 183 查看

题目

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

由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可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);
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hash