[POI2006]OKR-Periods of Words

时间:2023-12-19 17:30:20

题目描述

一个串是有限个小写字符的序列,特别的,一个空序列也可以是一个串. 一个串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]]已经是最优,
不需要再往前找了
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
char s[];
int k,nxt[];
long long ans;
int main()
{char ch;
int i,j;
cin>>k;
ch=getchar();
for (i=;i<=k;i++)
{
scanf("%c",&s[i]);
}
nxt[]=;j=;
for (i=;i<=k;i++)
{
while (j&&s[j+]!=s[i]) j=nxt[j];
if (s[j+]==s[i]) j++;
nxt[i]=j;
}
for (i=;i<=k;i++)
if (nxt[nxt[i]])
nxt[i]=nxt[nxt[i]];
for (i=;i<=k;i++)
if (nxt[i]) ans+=i-nxt[i];
cout<<ans;
}