洛谷3435 POI2006 OKR-Periods of Words

本文介绍了一种使用KMP算法求解字符串周期的方法,包括如何计算最长相同前后缀长度,并通过递推求解最短相同前后缀长度,进而找到字符串的最小周期和最大周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:OKR-Periods of Words

 

思路:

用kmp的做法先求出这个字符串的nxt[](最长相同前缀后缀)。

假设有这样一个字符串,nxt=2,这个字符串的最大周期就是6,最小周期就是5:

 XX XX YY YY YY  XX XX

 |       最大周期=6      |

|    最小周期=5   |  nxt=2 |

从最小周期来看,我们可以看出最小周期长==nxt。

因为两个最小周期和原串比就是:

XX XX XX XX XX XX XX XX   (两个最小周期)

XX XX XX XX XX XX             (原串)

|           A      |    B   |

A部分为原来的最小周期。因为两串的A+B部分是完全相同的,由于最小周期是原串的一个前缀,所以A部分也一定相同,相减得到B部分也定相同。而在最小周期中看,B部分是原串的一个前缀;在原串中看,B又是原串的一个后缀。所以一个周期的长度=原串长 - 某一个相同前缀后缀的长。那么最小周期长=原串长 - 最长相同前缀后缀的长=原串长-nxt。

同理:最大周期=原串长 - 最短相同前后缀的长。

最短相同前后缀长怎么求呢?

设t[]为最短相同前缀后缀长。

可以递推求解:t[i] = t[ nxt[i] ] , i∈[0,len-1] ,说汉语就是 原串的最长相同前后缀的最短相同前后缀 也就是 原串的最短相同前后缀。i正着从0开始循环,所以可以保证t[nxt[i]]的值是已经求过了的。

特别的,当nxt[i]=-1时,t[i]=i。

 

代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 1000000
#define ll long long

int n;
char a[maxn+5];
int nxt[maxn+5];
int t[maxn+5];

int main(){
	scanf("%d",&n);
	scanf("%s",a);
	
	nxt[0]=-1;
	for(int i=1;i<n;i++){
		int j=nxt[i-1];
		while(a[j+1]!=a[i]&&j>=0) {
			j=nxt[j];
		}
		if(a[j+1]==a[i]) nxt[i]=j+1;
		else nxt[i]=-1;
	}
	
	for(int i=0;i<n;i++){
		if(nxt[i]==-1) t[i]=i;
		else t[i]=t[nxt[i]];
	}
	
	ll ans=0;
	for(int i=0;i<n;i++){
		if(~t[i]) ans+=i-t[i];
	}
	printf("%lld",ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值