[POI2006]OKR-Periods of Words
题目描述
一个串是有限个小写字符的序列,特别的,一个空序列也可以是一个串. 一个串P是串A的前缀, 当且仅当存在串B, 使得 A = PB. 如果 P A 并且 P 不是一个空串,那么我们说 P 是A的一个proper前缀. 定义Q 是A的周期, 当且仅当Q是A的一个proper 前缀并且A是QQ的前缀(不一定要是proper前缀). 比如串 abab 和 ababab 都是串abababa的周期. 串A的最大周期就是它最长的一个周期或者是一个空串(当A没有周期的时候), 比如说, ababab的最大周期是abab. 串abc的最大周期是空串. 给出一个串,求出它所有前缀的最大周期长度之和.。
输入输出样例
输入样例#1:
8 babababa
输出样例#1:
24
最长循环串长度=总长度-最短相同前后缀长度(也就是kmp中的next)
但我们的kmp求的是最长相同前后缀长度
举个例子:
abababa next[7]=5,所以abababa可以由两个ababa组成
同理ababa可以由aba组成
aba可以由a组成
a的next=0,所以结束
因此,a一定既是abababa的前缀,又是它的后缀,并且是最小的
这样每次我们都用上法处理O(n^2)
可以利用前面更新的next,用O(1)的时间更新next
方法:
如果next[next[i]]!=0则next[i]=next[next[i]]
因为按此方法,前面得到的肯定是最短的next,此刻对于next[next[i]]已经是最优,
不需要再往前找了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 char s[1000001]; 8 int k,nxt[1000001]; 9 long long ans; 10 int main() 11 {char ch; 12 int i,j; 13 cin>>k; 14 ch=getchar(); 15 for (i=1;i<=k;i++) 16 { 17 scanf("%c",&s[i]); 18 } 19 nxt[1]=0;j=0; 20 for (i=2;i<=k;i++) 21 { 22 while (j&&s[j+1]!=s[i]) j=nxt[j]; 23 if (s[j+1]==s[i]) j++; 24 nxt[i]=j; 25 } 26 for (i=1;i<=k;i++) 27 if (nxt[nxt[i]]) 28 nxt[i]=nxt[nxt[i]]; 29 for (i=1;i<=k;i++) 30 if (nxt[i]) ans+=i-nxt[i]; 31 cout<<ans; 32 }