[HDU3068]最长回文

[HDU3068]最长回文

试题描述

给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等

输入

输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000

输出

每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.

输入示例

aaaa
abab

输出示例

4
3

数据规模及约定

见“输入

题解

学习了一下 manacher 算法,O(n) 求出以每个位置为中心的最长回文串长度,这个算法主要利用了“若回文串前半部分的某个子串是回文串,那么它的后半部分对应位置的子串是一模一样的回文串”,详情请百度,随便找一个博客上都解释得很清楚。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

#define maxn 220010
char Str[maxn], S[maxn];
int Len[maxn], alp[maxn];

int main() {
    while(scanf("%s", Str + 1) == 1) {
        int n = strlen(Str + 1);
        for(int i = 1; i <= n; i++) S[(i<<1)-1] = Str[i], S[i<<1] = '#';
        n <<= 1; n--;
        for(int i = 1; i <= n; i++) alp[i] = alp[i-1] + ('a' <= S[i] && S[i] <= 'z');
        int mxi = 0, ans = 0;
        for(int i = 1; i <= n; i++) {
            int mxp = mxi + Len[mxi] - 1;
            if(mxp < i) Len[i] = 1;
            else Len[i] = min(Len[(mxi<<1)-i], mxp - i + 1);
            while(1 <= i - Len[i] + 1 && i + Len[i] - 1 <= n && S[i-Len[i]+1] == S[i+Len[i]-1])
                Len[i]++;
            Len[i]--;
            if(mxp < i + Len[i] - 1) mxi = i;
            int l = i - Len[i] + 1, r = i + Len[i] - 1;
            ans = max(ans, alp[r] - alp[l-1]);
        }
        printf("%d\n", ans);
    }
    
    return 0;
}

 

posted @ 2017-02-11 13:07  xjr01  阅读(465)  评论(0编辑  收藏  举报