5178. 【NOIP2017提高组模拟6.28】So many prefix? (Standard IO)

Description

PCY学生物学累了。突然看到地上有一本笔记本。
上面写着“isdashagaydashisorosdashnot...”之类的字眼,独具慧眼的他发现这些字符串中有着大秘密!类似“isdash”这样的前缀在字符串中出现的次数不止一次!他觉得这其中一定有蹊跷,于是开始一个一个数前缀出现的次数。
虽然他早已经从逐字符匹配转换到了多行同时匹配模式,但是这小小的练习本上几十万个字符还是让他措手不及。你能帮助他吗?他想知道所有长度为偶数的前缀在整个字符串出现的次数和。

Input

共一行,一个字符串s。

Output

共一行,输出一个整数,代表长度为偶数的前缀在整个字符串出现的次数和。

Solution

KMP + DP,考虑 KMP 中的 next[i],

代表最大的 k(k!=i) 使‘s[1]s[2]…s[k]==s[i–k+1]s[i–k]…s[i]’,

那么我们设f[i]代表以i前缀‘s[1]s[2]…s[i]’内所有偶数子串出现的次数(包含本身),

得到:


时间复杂度 O(n)

代码

 1 var
 2   l,ans:longint;
 3   s:ansistring;
 4   next,f:array [0..200001] of longint;
 5 procedure main;
 6 var
 7   i,j:longint;
 8 begin
 9   j:=0; l:=length(s);
10   for i:=2 to l do
11     begin
12       while (j>0) and (s[j+1]<>s[i]) do
13         j:=next[j];
14       if s[j+1]=s[i] then j:=j+1;
15       next[i]:=j;
16     end;
17   fillchar(f,sizeof(f),0);
18   ans:=0;
19   for i:=2 to l do
20     begin
21       if i mod 2=0 then f[i]:=f[i]+1;
22       f[i]:=f[i]+f[next[i]];
23       ans:=ans+f[i];
24     end;
25   writeln(ans);
26 end;
27 
28 begin
29   readln(s);
30   main;
31 end.
原文地址:https://www.cnblogs.com/zyx-crying/p/9464771.html