洛谷 P3435 [POI2006] OKR-Periods of Words 题解

题目链接

如下图所示,bababababa 的 proper 前缀。

捕获.PNG

我们想要 porper 前缀(即红色部分)的长度尽量长,就要框中绿色部分尽量短。又必须满足框中绿色部分是红色部分的前缀。容易发现绿色部分即是框中字符串的前缀又是字符串的后缀,这时问题就转化成了求字符串最短的即是前缀又是后缀的子串长度。

接下来思考如何求这个字串的长度。

设数组 \(a\) 为前缀函数,则有 \(a[a[|s|]]\) 也满足既是 \(s\) 前缀又是 \(s\) 后缀,所以只需要在长度大于 \(0\) 时一直递推这个长度即可得出绿色部分,答案就呼之欲出了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1000100;
int n,a[N];
ll ans;
string s;
int main()
{
	cin>>n>>s;
	s=" "+s;
	for(int i=1,j=0;i<n;i++)
	{
		while(j&&s[i+1]!=s[j+1]) j=a[j];
		if(s[i+1]==s[j+1]) j++;
		a[i+1]=j;
	}
	for(int i=1,j=0;i<=n;i++)
	{
		j=i;
		while(a[j]>0) j=a[j];
		if(a[i]>0) a[i]=j;
		ans+=i-j;
	}
	printf("%lld",ans);
	return 0;
}
posted @ 2024-08-12 11:10  MinimumSpanningTree  阅读(18)  评论(0)    收藏  举报