单词检索

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

由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可N篇文章,每篇文章为一个字符串。现在,校长需要他找到这样的单词,它至少在这N篇文章中的M篇文章里出现过,且单词长度为L。可是,工作量十分庞大,但校长又急需小可可完成这项任务。

现在他向你求助,需要你编写程序完成这项艰巨的任务。

输入
第1行3个正整数N,M,L,表示文章的数目,单词至少出现在M篇文章中和每个单词的长度。

接下来N行,每行一个字符串,表示一篇文章。

输出
仅一行,表示满足检索条件的单词数。

样例输入
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,均有小写字母组成。

对于每个字符串,把里面所有长度为L的字符串hash记录,查找就可以了,注意同意字符串里的重复子串。

const p=2999999;
var
n,m,l,i,j,k,len,tot,h:longint;
tmp1,tmp2,ans:int64;
s:ansistring;
fac1,fac2:array[0..1011] of int64;
head,a,sum,ret,next:array[0..2999999] of longint;
flag,f:array[0..2999999] of boolean;
procedure ins(tmp1,tmp2:longint);
var
i:longint;
begin
  i:=head[tmp1];
  while i<>0 do
  begin
    if ret[i]=tmp2 then
    begin
      if f[i] then exit;
      sum[i]:=sum[i]+1;
      if (sum[i]>=m)and(flag[i]=false) then
      begin
        flag[i]:=true;
        ans:=ans+1;
      end;
      h:=h+1; f[i]:=true;  a[h]:=i;
      exit;
    end;
    i:=next[i];
  end;
  tot:=tot+1;
  ret[tot]:=tmp2;
  sum[tot]:=1;
  h:=h+1; f[tot]:=true; a[h]:=tot;
  if m=1 then begin ans:=ans+1; flag[i]:=true; end;
  next[tot]:=head[tmp1];
  head[tmp1]:=tot;
end;

begin
  readln(n,m,l);
  fac1[0]:=1;
  fac2[0]:=1;
  for i:=1 to 1000 do
  begin
    fac1[i]:=fac1[i-1]*31 mod p;
    fac2[i]:=fac2[i-1]*41 mod p;
  end;
  for i:=1 to n do
  begin
    readln(s);
    len:=length(s);
    tmp1:=0;
    tmp2:=0;
    for j:=1 to l do
    begin
      tmp1:=(tmp1+(ord(s[j])-ord('Z'))*fac1[l-j+1] mod p) mod p;
      tmp2:=(tmp2+(ord(s[j])-ord('Z'))*fac2[l-j+1] mod p) mod p;
    end;
    ins(tmp1,tmp2);
    for j:=l+1 to len do
    begin
      tmp1:=(tmp1-(ord(s[j-l])-ord('Z'))*fac1[l] mod p+p) mod p;
      tmp2:=(tmp2-(ord(s[j-l])-ord('Z'))*fac2[l] mod p+p) mod p;
      tmp1:=(tmp1*31 mod p+(ord(s[j])-ord('Z'))*fac1[1] mod p) mod p;
      tmp2:=(tmp2*41 mod p+(ord(s[j])-ord('Z'))*fac2[1] mod p) mod p;
      ins(tmp1,tmp2);
    end;
    for j:=1 to h do
      f[a[j]]:=false;
    h:=0;
  end;
  write(ans);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值