HDU 4513 完美队形II (Manacher)

这道题有很多人用的是KMP的算法,据说KMP的时间复杂度是O(n*logn),但是用Manacher,就是O(n), 所以力挺MANA

这里面和正常求最长回文串不同的是,这个回文串要前半部分单调递增,当然,由于对称性,后半部分单调递减!

那么就要在原来的基础上,加上几个判断,保证回文串是满足以上要求的。

首先说,最右侧在sign的位置,那么一定是要将最长回文串长度加1的,这是显而易见的,对称嘛;

其次说,如果是在回文串数据的位置,就要在最右面或最左边,减2或加2来对比是不是满足要求。而这里有两种可能,如果当前的数字是数据的话,那就只要判断数据大小,但是如果是sign的话,那么就要判断最右侧的位置减2的位置在哪里,可能在当前位置的右侧,就相当于原串有这样的子串,“23 23”,这样的话也当然要加1了,然后接下来要判断的是再进一步扩展的数据的大小。

画个图就会发现一共就这三种可能,尤其是sign两侧的相同的数据,这个可能要好好考虑,不能落下

代码:

//最长回文串
#include 
#include 
#include 
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);
        }
    }
}
                


你可能感兴趣的:(String)