1026 - KMP - OKR-Periods of Words[POI2006]

版权声明:虽然我只是个小蒟蒻但转载也请注明出处哦 https://blog.csdn.net/weixin_42557561/article/details/83414084

传送门

Little Tip

这道题,千万不要看中文翻译!!!
我一开始就看的中文,看得我一脸懵逼,什么什么什么鬼啊
后来看了题解,还是一脸懵逼
再后来滚去看英文版本的,喔~~~
豁然开朗
不过既然都说到这个份上了
大家是不是都觉得我要翻译一下了啊
当然不是。
自己去翻。
英文还是蛮好懂的

分析

KMP是真的妙,一定要深入理解 n x t [ i ] nxt[i] 的含义

n x t [ i ] nxt[i] : 以 i i 作为结尾的,最长的,相同前后缀的长度

小栗子献上:
a b c a b abcab n x t [ 5 ] = 2 n x t [ 4 ] = 1 , n x t [ 3 ] = 0 , n x t [ 2 ] = 0 , n x t [ 1 ] = 0 nxt[5]=2,nxt[4]=1,nxt[3]=0,nxt[2]=0,nxt[1]=0

对于这道题,我们需要求串A的每一个前缀的最大周期之和
也就是求任意一个串的最大周期,然后相加
最大周期就是,,,我们先定义串B:满足B是A的一个前缀,且A是两倍B的前缀
最大周期就是串B的最大的长度
来看一张图
(图摘自洛谷)
在这里插入图片描述
我们发现 i n x t [ i ] i-nxt[i] 就是一个周期,当 n x t [ i ] nxt[i] 最小的时候,求得的就是最大周期
这同时也满足了A是两倍串B的条件,为什么呢?
n x t [ i ] > l e n i / 2 nxt[i]>leni/2 ,此时 i n x t [ i ] < l e n i / 2 i-nxt[i]<leni/2 肯定是错误的
但由于我们始终是在找 n x t [ i ] nxt[i] 的最小值,当 n x t [ i ] > l e n i / 2 nxt[i]>leni/2 时,肯定还可以找到更小的
在这里插入图片描述
最后我们稍微优化一下


Code

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
char st[1000009];
int nxt[1000009];
int main(){
	int len,i,j;
	scanf("%d",&len);
	scanf("%s",st+1);
	nxt[1]=0;j=0;
	for(i=2;i<=len;++i){
		while(j&&st[j+1]!=st[i]) j=nxt[j];
		if(st[j+1]==st[i]) j++;
		nxt[i]=j;
	}
	ll ans=0;
	for(i=1;i<=len;++i){
		j=i;
		while(nxt[j]) j=nxt[j];
		if(nxt[i]) nxt[i]=j;//优化
		ans+=1ll*(i-j);
	}
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42557561/article/details/83414084