这道题有很多人用的是KMP的算法,据说KMP的时间复杂度是O(n*logn),但是用Manacher,就是O(n), 所以力挺MANA
这里面和正常求最长回文串不同的是,这个回文串要前半部分单调递增,当然,由于对称性,后半部分单调递减!
那么就要在原来的基础上,加上几个判断,保证回文串是满足以上要求的。
首先说,最右侧在sign的位置,那么一定是要将最长回文串长度加1的,这是显而易见的,对称嘛;
其次说,如果是在回文串数据的位置,就要在最右面或最左边,减2或加2来对比是不是满足要求。而这里有两种可能,如果当前的数字是数据的话,那就只要判断数据大小,但是如果是sign的话,那么就要判断最右侧的位置减2的位置在哪里,可能在当前位置的右侧,就相当于原串有这样的子串,“23 23”,这样的话也当然要加1了,然后接下来要判断的是再进一步扩展的数据的大小。
画个图就会发现一共就这三种可能,尤其是sign两侧的相同的数据,这个可能要好好考虑,不能落下
代码:
//最长回文串
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100100;
int T, n, id, Maxl, Maxid, p[N<<1];
int s[N], str[N<<1];
void kp() {
for ( int i = 1; i < n; ++i ) {
if ( Maxid > i ) p[i] = min( Maxid-i, p[id*2-i] );
else p[i] = 1;
while ( str[i+p[i]] == str[i-p[i]] ) {
if ( str[i+p[i]] == 2 ) p[i]++;
else if ( ( i+p[i]-2 < i ) || str[i+p[i]] <= str[i+p[i]-2] ) p[i]++;
else break;
}
if ( Maxid < p[i] + i ) {
Maxid = p[i]+i;
id = i;
}
if ( p[i] > Maxl ) Maxl = p[i];
}
}
int main()
{
while ( scanf("%d", &T) != EOF ) {
while ( T-- ) {
scanf("%d", &n);
memset( str, 0, sizeof(str) );
str[0] = -1; str[1] = 2;
int j = 2;
for ( int i = 0; i < n; ++i ) {
scanf("%d", &str[j++]);
str[j++] = 2;
}
n = j; str[n] = -2;
//printf("%d\n", n);
//for ( int i = 0; i < n; ++i ) printf(" %d", str[i]);
id = Maxid = Maxl = 0;
kp();
printf("%d\n", Maxl - 1);
}
}
}