Girls' research - HDU 3294 (Manacher处理回文串)

题目大意:给以一个字符串,求出来这个字符串的最长回文串,不过这个字符串不是原串,而是转换过的,转换的原则就是先给一个字符 例如 'b' 意思就是字符把字符b转换成字符 a,那么c->b, d->c.....a->z,大致就是这么个意思,然后求出最大回文串就行(回文串至少长度也得等于2)。
 
分析:字符转换没什么可说的,求回文串可以使用Manacher算法,主要说一下怎么用 p数组保存的信息求原来的区间,因为p保存的是扩展串的匹配数目,p[i]就是保存的最大匹配值,我们可以先求出来它的最左端是 L=i-p[i]+1, 其实这个最左端保存的值一定是一个'#',因为‘#’总会被匹配成功,实际的串的位置肯定在这个字符的右边L+1,因为扩展的时候实际字符是按照i+i+2来计算的,所以还原的时候应该是 (L+1-2)/2,也就是(i-p[i])/2;
 
代码如下:
==============================================================================================================
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

const int MAXN = 1e6+7;
const int oo = 1e9+37;

char s[MAXN];
int  p[MAXN];

int Manacher(int len)
{
    int id=0, Max=0;

    for(int i=2; i<len; i++)
    {
        p[i] = 1;

        if(p[id]+id > i)
            p[i] = min(p[id*2-i], p[id]+id-i);

        while( s[ i+p[i] ] == s[ i-p[i] ] )
            p[i]++;

        if(p[id]+id < p[i]+i)
            id = i;

        if(p[Max] < p[i])
            Max = i;
    }

    return Max;
}

int main()
{
    char ch[10]={0};

    while(scanf("%s%s", ch, s) != EOF)
    {
        int i, k=ch[0]-'a';
        int N = strlen(s);

        for(i=N; i>=0; i--)
        {
            if(i != N)
            {
                s[i] -= k;
                if(s[i] < 'a')
                    s[i] += 26;
            }
            s[i+i+2] = s[i];
            s[i+i+1] = '#';
        }
        s[0] = '$';

        k = Manacher(N+N+1);

        if(p[k] <= 2)
            printf("No solution!\n");
        else
        {

            int L = (k-p[k])/2, R = k+p[k];

            printf("%d %d\n", L, L+p[k]-2);

            for(i=k-p[k]+1; i<R; i++)
            {
                if(s[i] != '#')
                    printf("%c", s[i]);
            }
            printf("\n");
        }
    }

    return 0;
}

 

posted @ 2015-08-22 11:30  无忧望月  阅读(116)  评论(0编辑  收藏  举报
levels of contents