【ybtoj】【kmp】周期长度和

推荐一篇dalao写的博客:wind_whisper

题意

题解

首先想想题里说的周期和kmp里的 nxt 数组有没有什么关系

对于一个长度为 i 的串,i - nxt[i]就是一个周期的长度(不一定最大)

假设 i - nxt[i] > i/2 ,即一个串的最短(前缀=后缀)的长度一定小于等于这个串的一半

可以想象,把一个串的 1 ~ i - nxt[i] 的部分复制一倍接在后面,一定能使原来的整串成为新的串的前缀

但是 i - nxt[i] <i/2 的话,显然长度上就不满足,但这种情况(即一个串的最短(前缀=后缀)的长度一大于这个串的一半)是不存在的,具体见下图

(假设黑色的部分是最短的(前缀=后缀),就能证明出还存在更短的红色部分(前缀=后缀))

在这里插入图片描述

同时,这里连续跳 nxt 数组的过程可以用类似并查集路径压缩的方式优化,值得学习

代码

周期长度和
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 1e6+10;
int nxt[N],n;
ll ans;
char s[N];
void pre()
{
	int j=0;
	nxt[1]=0;
	for(int i=1;i<n;i++)	
	{
		while(s[i+1]!=s[j+1]&&j) j=nxt[j];
		if(s[i+1]==s[j+1]) j++;
		nxt[i+1]=j;
	}
}
int find(int x)
{
	if(nxt[x]) return nxt[x]=find(nxt[x]);
	return x;
int main()
{
	scanf("%d%s",&n,s+1);
	pre();
	for(int i=1;i<=n;i++)	
		ans+=i-find(i);
		//(我原本从nxt[i]开始错了)从i开始,因为当nxt[i]==0时没有周期 
	printf("%lld",ans);
	return 0;
}

 

posted @ 2021-09-06 15:48  conprour  阅读(38)  评论(0编辑  收藏  举报