好文章
时间限制:1000MS内存限制:256000KB
题目描述
nodgd写了一篇文章,自认为这是一篇好文章。nodgd的文章由n个小写英文字母组成。文章的一个子串指的是文章中的一段连续的字母,子串的长度就是这一段的字母个数。nodgd在文章中用了排比、对偶、前后照应之类的手法,所以就有很多个子串是相同或者相近的。为了向大家证明这是一篇好文章,nodgd决定给自己的文章进行评分。nodgd首先确定了一个整数m,然后统计出文章中有多少个不相同的长度为m的子串,这个数量就是文章的评分。
然而,nodgd懒得老老实实计算这个评分了,就把任务丢给了你。
输入
第一行包含两个整数n,m,表示文章的长度和需要统计的子串长度。
第二行包含一个长度为n的只包含小写字母的字符串。
输出
输出一行一个整数,表示文章的评分。
输入样例复制
输入1:
5 3
aaaab
输入2:
9 3
abcabacba
输出样例复制
输出1:
2
样例解释1:
长度为3的子串有3个,分别是aaa,aaa,aab,其中不同的只有2个。
输出2:
7
样例解释2:
共有7个长度为3的子串,每个长度为3的子串都不同。
说明
对于30%的数据,1≤m≤n≤200; 对于50%的数据,1≤m≤n≤2000; 对于另外20%的数据,1≤m≤50≤n≤200000; 对于100%的数据,1≤m≤n≤200000。
题解:字符串双哈希。哈希可用链表做
const
maxn=200000;
p1=100000009;
p2=100000007;
p=10000007;
inf='1021T3.in';
var
a:array[1..maxn]of char;
sum1,sum2:array[0..maxn]of int64;
h:array[0..p+1,1..2]of int64;
last:array[0..p+1]of int64;
mul1,mul2:int64;
pp1,pp2,ans,pp:int64;
n,m,i,j,k,num:longint;
procedure init;
var
i:longint;
begin
readln(n,m);
for i:=1 to n do
begin
read(a[i]);
sum1[i]:=(sum1[i-1]*26+ord(a[i])-ord('a')+1)mod p1;
sum2[i]:=(sum2[i-1]*26+ord(a[i])-ord('a')+1)mod p2;
end;
mul1:=26;mul2:=26;
for i:=2 to m do
begin
mul1:=mul1*26 mod p1;
mul2:=mul2*26 mod p2;
end;
for i:=0 to p+1 do
begin
last[i]:=-1;
end;
end;
function hash(x,y:int64):boolean;
var
i:int64;
begin
x:=x mod p;
i:=last[x];
while true do
begin
if i=-1 then
begin
inc(num);
h[num,2]:=last[x];
last[x]:=num;
h[num,1]:=y;
break;
end;
if h[i,1]=y then exit(true);
i:=h[i,2];
end;
exit(false);
end;
begin
//assign(input,inf);reset(input);
init;
for i:=1 to n-m+1 do
begin
j:=i+m-1;
pp1:=(sum1[j]-(sum1[i-1]*mul1 mod p1)+p1)mod p1;
pp2:=(sum2[j]-(sum2[i-1]*mul2 mod p2)+p2)mod p2;
if hash(pp1,pp2)=false then
begin
inc(ans);
end;
end;
writeln(ans);
//close(input);
end.