[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 }

 

posted @ 2017-08-15 20:47  Z-Y-Y-S  阅读(238)  评论(0编辑  收藏  举报