【KMP】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的最大周期是空串。
给出一个串,求出它所有前缀的最大周期长度之和。
输入
第一行一个整数k,表示串的长度。
接下来一行表示给出的串。
输出
输出一个整数表示它所有前缀的最大周期长度之和。
样例输入
8 babababa
样例输出
24
提示
对于全部数据,1<k<1e6
【题意】:
看题意,人话吗?我真的看了很久很久,最后还是找博客上的解释才看懂是什么 意思。。。
参考博客:蒟蒻のblog
思路
先把题面转成人话:
对于给定串的每个前缀i,求最长的,使这个字符串重复两边能覆盖原前缀i的前缀(就是前缀i的一个前缀),求所有的这些“前缀的前缀”的长度和
利用nextnext的性质:前缀ii的长度为next[i]的前缀和后缀是相等的
这说明:如果有i一个公共前后缀长度为j,那么这个前缀i就有一个周期为i-j
见下图
显然图中蓝色线段是黑色线段的一个周期
那么接下来的问题就容易了:
先求出next数组
【代码】:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 1e6 + 10; 4 typedef long long ll; 5 char p[N]; 6 int Next[N],m; 7 8 void get_Hash(){ 9 for(int i=2,j=0; i<=m;i++){ 10 while( j && p[i] != p[j+1] ) j = Next[j]; 11 if( p[i] == p[j+1] ) j++; 12 Next[i] = j ; 13 } 14 } 15 int main() 16 { 17 scanf("%d",&m); 18 scanf("%s",p+1); 19 ll ans = 0 ; 20 get_Hash(); 21 for(int i=1;i<=m;i++){ 22 int j = i ; 23 while( Next[j] ) j = Next[j]; 24 if( Next[i] ) Next[i] = j ; 25 ans = ans + (i-j); 26 } 27 printf("%lld\n",ans); 28 return 0 ; 29 }
原文地址:https://www.cnblogs.com/Osea/p/11333584.html
时间: 2024-10-19 17:04:54