Prefixes and Suffixes

题面
给你一个长度为n的长字符串,“完美子串”既是它的前缀也是它的后缀,求“完美子串”的个数且统计这些子串的在长字符串中出现的次数。

很自然地往 KMP 的方向想,根据 fail 数组可以很容易地算出完美字串的个数,但发现每个串出现次数只能 O ( N ) O(N) O(N) 处理,那么全部的最坏复杂度为 O ( N 2 ) O(N^2) O(N2)

这时候很容易在考虑 KMP 上陷进去,如何处理每个前缀串的出现次数?注意到是前缀串,考虑扩展KMP。

完美子串依旧很好求, i + Z i − 1 = n i+Z_i-1=n i+Zi1=n Z i Z_i Zi 指 Z 函数。出现次数可以通过用桶存 Z i Z_i Zi 再求后缀和求得,结论很显然。

整题关键在于想到扩K求解。

code
#include
using namespace std;
const int N=1e5+5;
char s[N];
int n,tot,nt[N],t[N];
void ExKMP(){
	nt[0]=n;
	int p=0;
	while (p+1<n&&s[p]==s[p+1]) p++;
	nt[1]=p;
	int k=1;
	for(int i=2;i<n;i++){
		p=k+nt[k]-1;
		int l=nt[i-k];
		if(i+l-1<p) nt[i]=l;
		else{
			int j=max(0,p-i+1);
			while (i+j<n&&s[j]==s[i+j]) j++;
			nt[i]=j;
			k=i;
		}
	}return ;
}
int main(){
	scanf("%s",s);
	n=strlen(s);
	ExKMP();
	for(int i=0;i<n;i++) t[nt[i]]++;
	for(int i=n-1;~i;i--) t[i]+=t[i+1];
	for(int i=0;i<n;i++) if(i+nt[i]==n) tot++;
	printf("%d\n",tot);
	for(int i=n-1;~i;i--) if(i+nt[i]==n) printf("%d %d\n",nt[i],t[nt[i]]);
	return 0;
}
/*
start coding:15:15
finish debuging:15:35
*/

你可能感兴趣的:(题解,总结与反思,学习,算法,c++,扩展KMP,线性代数)