最长回文 hdu 3068 poj 3974 ural 1297

http://acm.hdu.edu.cn/showproblem.php?pid=3068

http://poj.org/problem?id=3974

http://acm.timus.ru/problem.aspx?space=1&num=1297

题意:给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.

思路:

1、Manacher解法,再每个字母前后面插入字符'#',再找最长回文串。

2、拓展KMP解法

3、后缀数组解法(超时了)

4、二分+暴力(水过)

解法4:(三个题目都可以这样解)明显,如果回文的长度是L,那么答案一定不小于L,因而能够二分答案。在判断L是否满足的时候,可以这样做:

sum[a]是前a个字符串和;

如果L是偶数,且sum[a]-sum[a-L/2]=sum[L/2+a] - sum[a],则开始进行回文匹配。

如果L是奇数,且sum[a-1]-sum[a-L/2-1]=sum[L/2+a]-sum[a];则开始进行回文匹配。

二分的时候先进行奇性匹配,因为L+1>L;如果成功则返回。

View Code
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<bitset>
#include<string>
#include<climits>
#include<cstdio>
#include<vector>
#include<utility>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define IN puts("in")
#define OUT puts("out")
#define FR(x) freopen(x,"r",stdin)
#define FW(x) freopen(x,"w",stdout)
#define MSET(x,y) memset(x,y,sizeof(x))
#define ST system("pause")
#define NU(x) (x[0]*1000+x[1]*100+x[2]*10+x[3])
using namespace std;

const int maxn = 110005;

int as[maxn],L,flag;
char str[maxn];

int judge(int g)
{
        int i,k = 0;
        for(i = g; i + g <= L; ++ i)
        {
                if(i-g){
                        if(as[i-1]-as[i-g-1]==as[i+g]-as[i]){
                                k = g;
                                int s = i - 1;
                                int t = i + 1;
                                while(k){
                                        if(str[s-1]^str[t-1])break;
                                        s--; t++;
                                        k--;
                                }
                                if(!k){flag = 1; return 1;}
                        }
                }
        }
        for(i = g; i + g <= L; ++ i)
        {
                if(as[i]-as[i-g]==as[i+g]-as[i]){
                        k = g;
                        int s = i;
                        int t = i + 1;
                        while(k){
                                if(str[s-1]^str[t-1])break;
                                s--; t++;
                                k--;
                        }
                        if(!k){flag = 0; return 1;}
                }
        }
        return 0;

}

int main()
{
        int i,low,high,mid,ans;
        while(scanf("%s",str)==1){
                L = strlen(str);
                as[1] = str[0];
                for(i = 1; i < L; ++ i) as[i+1] = as[i] + str[i];
                low = 1; high = L / 2; ans = 1;
                while(low<=high){
                        mid = (low + high) >> 1;
                        if(judge(mid)){
                                i = mid * 2 + flag;
                                ans = max(ans,i);
                                low = mid + 1;
                        }else high = mid - 1;
                }
                printf("%d\n",ans);
        }
        return 0;
}

posted on 2012-07-08 10:01  aigoruan  阅读(516)  评论(0)    收藏  举报

导航