题目描述
小可可是学校图书馆的管理员,现在他接手了一个十分棘手的任务。
由于学校需要一些材料,校长需要在文章中检索一些信息。校长一共给了小可可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.