【ybt高效进阶2-3-3】周期长度和

周期长度和

题目链接:ybt高效进阶2-3-3

题目大意

给你一个串,要你求每个前缀的最大周期长度之和。
一个串的周期就是它是它的一个子串,但是不能是空串也不不能这个串本身,而且这个子串复制一遍之后形成一个新的字符串,这个新的字符串要包含原来的串。

思路

其实就是要找一个子串,复制一遍之后包含了原来串。对于每个子串倒要找长度最大的那个。

那我们其实就是要让原来的串分成两份,然后前面的那个包含后面的那个。然后周期就是前面的那个。
那我们看看怎样搞,才能让前面的包含后面的那个。
我们跟 KMP 联想一下,发下它就是 KMP。

那我们要让周期长度最大,就是要让前面的尽可能大,后面的尽可能小。
那后面的长度其实就是 KMP 的长度,那我们要让这个长度尽可能小,那就是要 KMP 更小?

那其实是要找到能匹配的最小的。那就是不断得递归 f a i l i fail_i faili 0 0 0,然后到 f a i l i = 0 fail_i=0 faili=0 的时候, i i i 就是最小的。
当然我们可以用类似并查集的思想来进行记忆化,从而减少时间。

代码

#include<cstdio>

using namespace std;

int n, j, fail[1000001];
long long ans;
char c[1000001];

int find(int now) {
    
    
	if (fail[now]) return fail[now] = find(fail[now]);
	return now;
}

int main() {
    
    
	scanf("%d", &n);
	scanf("%s", c + 1);
	
	j = 0;
	for (int i = 2; i <= n; i++) {
    
    //KMP
		while (j && c[i] != c[j + 1]) j = fail[j];
		if (c[i] == c[j + 1]) j++;
		fail[i] = j;
	}
	
	for (int i = 1; i <= n; i++) {
    
    
		ans += 1ll * i - 1ll * find(i);
	} 
	
	printf("%lld", ans);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/112978036