题目描述
题解
题目要求求除了其本身的最长循环节,实际上就是要求非0的最短失配。
但是如果直接求最短失配的话,应该在求出最长失配的基础上暴力向前蹦,这样的话时间承受不了。那么可以转化一下思路,最长循环节是有递推关系的,即f(i)+=f(T(i))+(i-T(i)),T为失配函数。这样的话时间就可以做到
O(n)
了。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 1000005
#define LL long long
int n,T[N];
char s[N];
LL f[N],ans;
void calc_T()
{
T[0]=-1;
for (int i=0;i<n;++i)
{
int j=T[i];
while (j!=-1&&s[i]!=s[j])
j=T[j];
T[i+1]=++j;
}
}
int main()
{
scanf("%d\n",&n);
gets(s);
calc_T();
for (int i=1;i<=n;++i)
if (T[i])
{
f[i]+=f[T[i]]+((LL)i-(LL)T[i]);
ans+=f[i];
}
printf("%lld\n",ans);
}
总结
①kmp的失配可以与dp(还有树结构)联系起来!这一点以后要注意!