OKR-Periods of Words

OKR-Periods of Words ⁡ \operatorname{OKR-Periods\ of\ Words} OKR-Periods of Words

题目链接: luogu P3435 ⁡ \operatorname{luogu\ P3435} luogu P3435

题目大意

对于一个仅含小写字母的字符串 a a a p p p a a a 的前缀且 p ≠ a p\ne a p=a ,那么我们称 p p p a a a 的 proper 前缀。

规定字符串 Q Q Q (可以是空串)表示 a a a 的周期,当且仅当 Q Q Q a a a 的 proper 前缀且 a a a Q + Q Q+Q Q+Q 的前缀。

例如 ab 是 abab 的一个周期,因为 ab 是 abab 的 proper 前缀,且 abab 是 ab+ab 的前缀。

求给定字符串所有前缀的最大周期长度之和。

题目

A string is a finite sequence of lower-case (non-capital) letters of the English alphabet. Particularly, it may be an empty sequence, i.e. a sequence of 0 letters. By A=BC we denotes that A is a string obtained by concatenation (joining by writing one immediately after another, i.e. without any space, etc.) of the strings B and C (in this order). A string P is a prefix of the string !, if there is a string B, that A=PB. In other words, prefixes of A are the initial fragments of A. In addition, if P!=A and P is not an empty string, we say, that P is a proper prefix of A.

A string Q is a period of Q, if Q is a proper prefix of A and A is a prefix (not necessarily a proper one) of the string QQ. For example, the strings abab and ababab are both periods of the string abababa. The maximum period of a string A is the longest of its periods or the empty string, if A doesn’t have any period. For example, the maximum period of ababab is abab. The maximum period of abc is the empty string.

Task Write a programme that:

reads from the standard input the string’s length and the string itself,calculates the sum of lengths of maximum periods of all its prefixes,writes the result to the standard output.

输入

In the first line of the standard input there is one integer kk (1\le k\le 1\ 000\ 0001≤k≤1 000 000) - the length of the string. In the following line a sequence of exactly kk lower-case letters of the English alphabet is written - the string.

输出

In the first and only line of the standard output your programme should write an integer - the sum of lengths of maximum periods of all prefixes of the string given in the input.

样例输入

8
babababa

样例输出

24

思路

这道题是一道 KMP 。

先正常跟自己匹配得出 c a n n o t [ i ] cannot[i] cannot[i] ,就是匹配到 i i i 失败的时候下一次能从哪里开始。

然后我们来看看怎么求答案。

我们先举个例子: a b c a b c a b abcabcab abcabcab ,那肯定是选 a b c a b c abcabc abcabc 这个前缀。因为 a b c a b c a b abcabcab abcabcab 是它复制之后的字符串 a b c a b c a b c a b c abcabcabcabc abcabcabcabc 的前缀,而且 a b c a b c abcabc abcabc 这个前缀是最长的。
我们可以发现,剩下没有被选的 a b ab ab 是要等于前面的 a b ab ab 的,就是“前缀等于后缀”。
而且我们还可以发现,这个没有被选的字符串越小,前面的前缀越大。那我们就要让它最小,就是最小匹配长度。

但是问题来了, KMP 得到的是最长匹配长度,但是我们要的是最短匹配长度啊!
那我们就是找到最后一个公共前缀后缀,那可以通过一直让 j j j i i i 开始 j = c a n n o t [ j ] j=cannot[j] j=cannot[j] ,直到 c a n n o t [ j ] = = 0 cannot[j]==0 cannot[j]==0
显而易见, 对于这个前缀答案就是 i − j i-j ij

(当然可以每次跳完之后让 c a n n o t [ i ] = j cannot[i]=j cannot[i]=j ,就是记忆化)

记得开 long long 。

代码

#include
#define ll long long

using namespace std;

ll n, cannot[1000001], ans;
char a[1000001];
int j;

int main() {
	scanf("%lld", &n);//读入
	scanf("%s", a + 1);
	
	for (int i = 2; i <= n; i++) {//跟自己匹配
		while (j && a[i] != a[j + 1]) j = cannot[j];
		if (a[i] == a[j + 1]) j++;
		cannot[i] = j;
	}
	for (int i = 2; i <= n; i++) {//两个字符串匹配
		j = i;
		while (cannot[j]) j = cannot[j];//找到最短匹配长度
		ans += i - j;//答案加上
		if (cannot[i]) cannot[i] = j;//记忆化
	}
	
	printf("%lld", ans);//输出
	
	return 0;
}

你可能感兴趣的:(#,字符串,KMP,字符串,最短匹配长度)