给定字符串 ,求所有中心子串的最大奇border长度,名词解释:
- 中心子串:中心位置和原字符串中心位置相同的子串,即原字符串头尾去掉相同数量的字符后剩下的子串。
- border:最长的子串,既是真前缀,又是后缀。
- 奇border:最长的奇数长度的子串,既是真前缀,又是后缀,不存在输出-1.
设 表示第 个( 从 开始)中心子串( )的最大奇border的长度.
结论: ,证明如下:
因为对于方案 ,有
.
也有
.
这保证了 至少有一个大于 的方案
.
即 ,所以结论成立。
然后就可以快乐枚举,边界是 。
检查 时,直接看 是否成立即可,使用后缀数组。
构建后缀数组复杂度 ,枚举复杂度 ,总复杂度
- border的递推以及其它递推过程中,很爱用到这个枚举上限依赖,第一次见到是在前缀函数的复杂度证明。
n&1==0
可能不会产生预期的结果,因为==
要比&
优先。
namespace SA{}
char str[M];
int ans[M];
int main(void)
{
int n = read();
scanf("%s", str);
SA::build(str, n, 128);
memset(ans, -1, sizeof(ans));
int lim = (n-1)/2;
if((n&1)==0 && str[n/2-1]==str[n/2]) ans[lim] = 1;
for(int i=lim-1; i>=0; --i)
for(int j=ans[i+1]+2; j>=0; j-=2)
if(SA::lcp(i, n-i-j)>=j)
ans[i]=j, j=-1;
for(int i=0; i<=lim; ++i)
printf("%d ",ans[i] );
return 0;
}